GCC Code Coverage Report


Directory: ./
File: Modules/posixmodule.c
Date: 2022-06-27 09:02:04
Exec Total Coverage
Lines: 1192 3317 35.9%
Functions: 126 276 45.7%
Branches: 615 2262 27.2%

Line Branch Exec Source
1 /* POSIX module implementation */
2
3 /* This file is also used for Windows NT/MS-Win. In that case the
4 module actually calls itself 'nt', not 'posix', and a few
5 functions are either unimplemented or implemented differently. The source
6 assumes that for Windows NT, the macro 'MS_WINDOWS' is defined independent
7 of the compiler used. Different compilers define their own feature
8 test macro, e.g. '_MSC_VER'. */
9
10 #define PY_SSIZE_T_CLEAN
11
12 #include "Python.h"
13 // Include <windows.h> before pycore internal headers. FSCTL_GET_REPARSE_POINT
14 // is not exported by <windows.h> if the WIN32_LEAN_AND_MEAN macro is defined,
15 // whereas pycore_condvar.h defines the WIN32_LEAN_AND_MEAN macro.
16 #ifdef MS_WINDOWS
17 # include <windows.h>
18 # include <pathcch.h>
19 #endif
20
21 #ifdef __VXWORKS__
22 # include "pycore_bitutils.h" // _Py_popcount32()
23 #endif
24 #include "pycore_call.h" // _PyObject_CallNoArgs()
25 #include "pycore_ceval.h" // _PyEval_ReInitThreads()
26 #include "pycore_fileutils.h" // _Py_closerange()
27 #include "pycore_import.h" // _PyImport_ReInitLock()
28 #include "pycore_initconfig.h" // _PyStatus_EXCEPTION()
29 #include "pycore_moduleobject.h" // _PyModule_GetState()
30 #include "pycore_object.h" // _PyObject_LookupSpecial()
31 #include "pycore_pystate.h" // _PyInterpreterState_GET()
32 #include "pycore_signal.h" // Py_NSIG
33
34 #include "structmember.h" // PyMemberDef
35 #ifndef MS_WINDOWS
36 # include "posixmodule.h"
37 #else
38 # include "winreparse.h"
39 #endif
40
41 #if !defined(EX_OK) && defined(EXIT_SUCCESS)
42 # define EX_OK EXIT_SUCCESS
43 #endif
44
45 /* On android API level 21, 'AT_EACCESS' is not declared although
46 * HAVE_FACCESSAT is defined. */
47 #ifdef __ANDROID__
48 # undef HAVE_FACCESSAT
49 #endif
50
51 #include <stdio.h> // ctermid()
52 #include <stdlib.h> // system()
53
54 /*
55 * A number of APIs are available on macOS from a certain macOS version.
56 * To support building with a new SDK while deploying to older versions
57 * the availability test is split into two:
58 * - HAVE_<FUNCTION>: The configure check for compile time availability
59 * - HAVE_<FUNCTION>_RUNTIME: Runtime check for availability
60 *
61 * The latter is always true when not on macOS, or when using a compiler
62 * that does not support __has_builtin (older versions of Xcode).
63 *
64 * Due to compiler restrictions there is one valid use of HAVE_<FUNCTION>_RUNTIME:
65 * if (HAVE_<FUNCTION>_RUNTIME) { ... }
66 *
67 * In mixing the test with other tests or using negations will result in compile
68 * errors.
69 */
70 #if defined(__APPLE__)
71
72 #if defined(__has_builtin)
73 #if __has_builtin(__builtin_available)
74 #define HAVE_BUILTIN_AVAILABLE 1
75 #endif
76 #endif
77
78 #ifdef HAVE_BUILTIN_AVAILABLE
79 # define HAVE_FSTATAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *)
80 # define HAVE_FACCESSAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *)
81 # define HAVE_FCHMODAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *)
82 # define HAVE_FCHOWNAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *)
83 # define HAVE_LINKAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *)
84 # define HAVE_FDOPENDIR_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *)
85 # define HAVE_MKDIRAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *)
86 # define HAVE_RENAMEAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *)
87 # define HAVE_UNLINKAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *)
88 # define HAVE_OPENAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *)
89 # define HAVE_READLINKAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *)
90 # define HAVE_SYMLINKAT_RUNTIME __builtin_available(macOS 10.10, iOS 8.0, *)
91 # define HAVE_FUTIMENS_RUNTIME __builtin_available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *)
92 # define HAVE_UTIMENSAT_RUNTIME __builtin_available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *)
93 # define HAVE_PWRITEV_RUNTIME __builtin_available(macOS 11.0, iOS 14.0, tvOS 14.0, watchOS 7.0, *)
94
95 # define HAVE_POSIX_SPAWN_SETSID_RUNTIME __builtin_available(macOS 10.15, *)
96
97 #else /* Xcode 8 or earlier */
98
99 /* __builtin_available is not present in these compilers, but
100 * some of the symbols might be weak linked (10.10 SDK or later
101 * deploying on 10.9.
102 *
103 * Fall back to the older style of availability checking for
104 * symbols introduced in macOS 10.10.
105 */
106
107 # ifdef HAVE_FSTATAT
108 # define HAVE_FSTATAT_RUNTIME (fstatat != NULL)
109 # endif
110
111 # ifdef HAVE_FACCESSAT
112 # define HAVE_FACCESSAT_RUNTIME (faccessat != NULL)
113 # endif
114
115 # ifdef HAVE_FCHMODAT
116 # define HAVE_FCHMODAT_RUNTIME (fchmodat != NULL)
117 # endif
118
119 # ifdef HAVE_FCHOWNAT
120 # define HAVE_FCHOWNAT_RUNTIME (fchownat != NULL)
121 # endif
122
123 # ifdef HAVE_LINKAT
124 # define HAVE_LINKAT_RUNTIME (linkat != NULL)
125 # endif
126
127 # ifdef HAVE_FDOPENDIR
128 # define HAVE_FDOPENDIR_RUNTIME (fdopendir != NULL)
129 # endif
130
131 # ifdef HAVE_MKDIRAT
132 # define HAVE_MKDIRAT_RUNTIME (mkdirat != NULL)
133 # endif
134
135 # ifdef HAVE_RENAMEAT
136 # define HAVE_RENAMEAT_RUNTIME (renameat != NULL)
137 # endif
138
139 # ifdef HAVE_UNLINKAT
140 # define HAVE_UNLINKAT_RUNTIME (unlinkat != NULL)
141 # endif
142
143 # ifdef HAVE_OPENAT
144 # define HAVE_OPENAT_RUNTIME (openat != NULL)
145 # endif
146
147 # ifdef HAVE_READLINKAT
148 # define HAVE_READLINKAT_RUNTIME (readlinkat != NULL)
149 # endif
150
151 # ifdef HAVE_SYMLINKAT
152 # define HAVE_SYMLINKAT_RUNTIME (symlinkat != NULL)
153 # endif
154
155 #endif
156
157 #ifdef HAVE_FUTIMESAT
158 /* Some of the logic for weak linking depends on this assertion */
159 # error "HAVE_FUTIMESAT unexpectedly defined"
160 #endif
161
162 #else
163 # define HAVE_FSTATAT_RUNTIME 1
164 # define HAVE_FACCESSAT_RUNTIME 1
165 # define HAVE_FCHMODAT_RUNTIME 1
166 # define HAVE_FCHOWNAT_RUNTIME 1
167 # define HAVE_LINKAT_RUNTIME 1
168 # define HAVE_FDOPENDIR_RUNTIME 1
169 # define HAVE_MKDIRAT_RUNTIME 1
170 # define HAVE_RENAMEAT_RUNTIME 1
171 # define HAVE_UNLINKAT_RUNTIME 1
172 # define HAVE_OPENAT_RUNTIME 1
173 # define HAVE_READLINKAT_RUNTIME 1
174 # define HAVE_SYMLINKAT_RUNTIME 1
175 # define HAVE_FUTIMENS_RUNTIME 1
176 # define HAVE_UTIMENSAT_RUNTIME 1
177 # define HAVE_PWRITEV_RUNTIME 1
178 #endif
179
180
181 #ifdef __cplusplus
182 extern "C" {
183 #endif
184
185 PyDoc_STRVAR(posix__doc__,
186 "This module provides access to operating system functionality that is\n\
187 standardized by the C Standard and the POSIX standard (a thinly\n\
188 disguised Unix interface). Refer to the library manual and\n\
189 corresponding Unix manual entries for more information on calls.");
190
191
192 #ifdef HAVE_SYS_UIO_H
193 # include <sys/uio.h>
194 #endif
195
196 #ifdef HAVE_SYS_SYSMACROS_H
197 /* GNU C Library: major(), minor(), makedev() */
198 # include <sys/sysmacros.h>
199 #endif
200
201 #ifdef HAVE_SYS_TYPES_H
202 # include <sys/types.h>
203 #endif /* HAVE_SYS_TYPES_H */
204
205 #ifdef HAVE_SYS_STAT_H
206 # include <sys/stat.h>
207 #endif /* HAVE_SYS_STAT_H */
208
209 #ifdef HAVE_SYS_WAIT_H
210 # include <sys/wait.h> // WNOHANG
211 #endif
212 #ifdef HAVE_LINUX_WAIT_H
213 # include <linux/wait.h> // P_PIDFD
214 #endif
215
216 #ifdef HAVE_SIGNAL_H
217 # include <signal.h>
218 #endif
219
220 #ifdef HAVE_FCNTL_H
221 # include <fcntl.h>
222 #endif
223
224 #ifdef HAVE_GRP_H
225 # include <grp.h>
226 #endif
227
228 #ifdef HAVE_SYSEXITS_H
229 # include <sysexits.h>
230 #endif
231
232 #ifdef HAVE_SYS_LOADAVG_H
233 # include <sys/loadavg.h>
234 #endif
235
236 #ifdef HAVE_SYS_SENDFILE_H
237 # include <sys/sendfile.h>
238 #endif
239
240 #if defined(__APPLE__)
241 # include <copyfile.h>
242 #endif
243
244 #ifdef HAVE_SCHED_H
245 # include <sched.h>
246 #endif
247
248 #ifdef HAVE_COPY_FILE_RANGE
249 # include <unistd.h>
250 #endif
251
252 #if !defined(CPU_ALLOC) && defined(HAVE_SCHED_SETAFFINITY)
253 # undef HAVE_SCHED_SETAFFINITY
254 #endif
255
256 #if defined(HAVE_SYS_XATTR_H) && defined(__GLIBC__) && !defined(__FreeBSD_kernel__) && !defined(__GNU__)
257 # define USE_XATTRS
258 #endif
259
260 #ifdef USE_XATTRS
261 # include <sys/xattr.h>
262 #endif
263
264 #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__APPLE__)
265 # ifdef HAVE_SYS_SOCKET_H
266 # include <sys/socket.h>
267 # endif
268 #endif
269
270 #ifdef HAVE_DLFCN_H
271 # include <dlfcn.h>
272 #endif
273
274 #ifdef __hpux
275 # include <sys/mpctl.h>
276 #endif
277
278 #if defined(__DragonFly__) || \
279 defined(__OpenBSD__) || \
280 defined(__FreeBSD__) || \
281 defined(__NetBSD__) || \
282 defined(__APPLE__)
283 # include <sys/sysctl.h>
284 #endif
285
286 #ifdef HAVE_LINUX_RANDOM_H
287 # include <linux/random.h>
288 #endif
289 #ifdef HAVE_GETRANDOM_SYSCALL
290 # include <sys/syscall.h>
291 #endif
292
293 #if defined(MS_WINDOWS)
294 # define TERMSIZE_USE_CONIO
295 #elif defined(HAVE_SYS_IOCTL_H)
296 # include <sys/ioctl.h>
297 # if defined(HAVE_TERMIOS_H)
298 # include <termios.h>
299 # endif
300 # if defined(TIOCGWINSZ)
301 # define TERMSIZE_USE_IOCTL
302 # endif
303 #endif /* MS_WINDOWS */
304
305 /* Various compilers have only certain posix functions */
306 /* XXX Gosh I wish these were all moved into pyconfig.h */
307 #if defined(__WATCOMC__) && !defined(__QNX__) /* Watcom compiler */
308 # define HAVE_OPENDIR 1
309 # define HAVE_SYSTEM 1
310 # include <process.h>
311 #else
312 # ifdef _MSC_VER
313 /* Microsoft compiler */
314 # define HAVE_GETPPID 1
315 # define HAVE_GETLOGIN 1
316 # define HAVE_SPAWNV 1
317 # define HAVE_EXECV 1
318 # define HAVE_WSPAWNV 1
319 # define HAVE_WEXECV 1
320 # define HAVE_PIPE 1
321 # define HAVE_SYSTEM 1
322 # define HAVE_CWAIT 1
323 # define HAVE_FSYNC 1
324 # define fsync _commit
325 # endif /* _MSC_VER */
326 #endif /* ! __WATCOMC__ || __QNX__ */
327
328 /*[clinic input]
329 # one of the few times we lie about this name!
330 module os
331 [clinic start generated code]*/
332 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=94a0f0f978acae17]*/
333
334 #ifndef _MSC_VER
335
336 #if defined(__sgi)&&_COMPILER_VERSION>=700
337 /* declare ctermid_r if compiling with MIPSPro 7.x in ANSI C mode
338 (default) */
339 extern char *ctermid_r(char *);
340 #endif
341
342 #endif /* !_MSC_VER */
343
344 #if defined(__VXWORKS__)
345 # include <vxCpuLib.h>
346 # include <rtpLib.h>
347 # include <wait.h>
348 # include <taskLib.h>
349 # ifndef _P_WAIT
350 # define _P_WAIT 0
351 # define _P_NOWAIT 1
352 # define _P_NOWAITO 1
353 # endif
354 #endif /* __VXWORKS__ */
355
356 #ifdef HAVE_POSIX_SPAWN
357 # include <spawn.h>
358 #endif
359
360 #ifdef HAVE_UTIME_H
361 # include <utime.h>
362 #endif /* HAVE_UTIME_H */
363
364 #ifdef HAVE_SYS_UTIME_H
365 # include <sys/utime.h>
366 # define HAVE_UTIME_H /* pretend we do for the rest of this file */
367 #endif /* HAVE_SYS_UTIME_H */
368
369 #ifdef HAVE_SYS_TIMES_H
370 # include <sys/times.h>
371 #endif /* HAVE_SYS_TIMES_H */
372
373 #ifdef HAVE_SYS_PARAM_H
374 # include <sys/param.h>
375 #endif /* HAVE_SYS_PARAM_H */
376
377 #ifdef HAVE_SYS_UTSNAME_H
378 # include <sys/utsname.h>
379 #endif /* HAVE_SYS_UTSNAME_H */
380
381 #ifdef HAVE_DIRENT_H
382 # include <dirent.h>
383 # define NAMLEN(dirent) strlen((dirent)->d_name)
384 #else
385 # if defined(__WATCOMC__) && !defined(__QNX__)
386 # include <direct.h>
387 # define NAMLEN(dirent) strlen((dirent)->d_name)
388 # else
389 # define dirent direct
390 # define NAMLEN(dirent) (dirent)->d_namlen
391 # endif
392 # ifdef HAVE_SYS_NDIR_H
393 # include <sys/ndir.h>
394 # endif
395 # ifdef HAVE_SYS_DIR_H
396 # include <sys/dir.h>
397 # endif
398 # ifdef HAVE_NDIR_H
399 # include <ndir.h>
400 # endif
401 #endif
402
403 #ifdef _MSC_VER
404 # ifdef HAVE_DIRECT_H
405 # include <direct.h>
406 # endif
407 # ifdef HAVE_IO_H
408 # include <io.h>
409 # endif
410 # ifdef HAVE_PROCESS_H
411 # include <process.h>
412 # endif
413 # ifndef IO_REPARSE_TAG_SYMLINK
414 # define IO_REPARSE_TAG_SYMLINK (0xA000000CL)
415 # endif
416 # ifndef IO_REPARSE_TAG_MOUNT_POINT
417 # define IO_REPARSE_TAG_MOUNT_POINT (0xA0000003L)
418 # endif
419 # include "osdefs.h" // SEP
420 # include <malloc.h>
421 # include <windows.h>
422 # include <shellapi.h> // ShellExecute()
423 # include <lmcons.h> // UNLEN
424 # define HAVE_SYMLINK
425 #endif /* _MSC_VER */
426
427 #ifndef MAXPATHLEN
428 # if defined(PATH_MAX) && PATH_MAX > 1024
429 # define MAXPATHLEN PATH_MAX
430 # else
431 # define MAXPATHLEN 1024
432 # endif
433 #endif /* MAXPATHLEN */
434
435 #ifdef UNION_WAIT
436 /* Emulate some macros on systems that have a union instead of macros */
437 # ifndef WIFEXITED
438 # define WIFEXITED(u_wait) (!(u_wait).w_termsig && !(u_wait).w_coredump)
439 # endif
440 # ifndef WEXITSTATUS
441 # define WEXITSTATUS(u_wait) (WIFEXITED(u_wait)?((u_wait).w_retcode):-1)
442 # endif
443 # ifndef WTERMSIG
444 # define WTERMSIG(u_wait) ((u_wait).w_termsig)
445 # endif
446 # define WAIT_TYPE union wait
447 # define WAIT_STATUS_INT(s) (s.w_status)
448 #else
449 /* !UNION_WAIT */
450 # define WAIT_TYPE int
451 # define WAIT_STATUS_INT(s) (s)
452 #endif /* UNION_WAIT */
453
454 /* Don't use the "_r" form if we don't need it (also, won't have a
455 prototype for it, at least on Solaris -- maybe others as well?). */
456 #if defined(HAVE_CTERMID_R)
457 # define USE_CTERMID_R
458 #endif
459
460 /* choose the appropriate stat and fstat functions and return structs */
461 #undef STAT
462 #undef FSTAT
463 #undef STRUCT_STAT
464 #ifdef MS_WINDOWS
465 # define STAT win32_stat
466 # define LSTAT win32_lstat
467 # define FSTAT _Py_fstat_noraise
468 # define STRUCT_STAT struct _Py_stat_struct
469 #else
470 # define STAT stat
471 # define LSTAT lstat
472 # define FSTAT fstat
473 # define STRUCT_STAT struct stat
474 #endif
475
476 #if defined(MAJOR_IN_MKDEV)
477 # include <sys/mkdev.h>
478 #else
479 # if defined(MAJOR_IN_SYSMACROS)
480 # include <sys/sysmacros.h>
481 # endif
482 # if defined(HAVE_MKNOD) && defined(HAVE_SYS_MKDEV_H)
483 # include <sys/mkdev.h>
484 # endif
485 #endif
486
487 #ifdef MS_WINDOWS
488 # define INITFUNC PyInit_nt
489 # define MODNAME "nt"
490 #else
491 # define INITFUNC PyInit_posix
492 # define MODNAME "posix"
493 #endif
494
495 #if defined(__sun)
496 /* Something to implement in autoconf, not present in autoconf 2.69 */
497 # define HAVE_STRUCT_STAT_ST_FSTYPE 1
498 #endif
499
500 /* memfd_create is either defined in sys/mman.h or sys/memfd.h
501 * linux/memfd.h defines additional flags
502 */
503 #ifdef HAVE_SYS_MMAN_H
504 # include <sys/mman.h>
505 #endif
506 #ifdef HAVE_SYS_MEMFD_H
507 # include <sys/memfd.h>
508 #endif
509 #ifdef HAVE_LINUX_MEMFD_H
510 # include <linux/memfd.h>
511 #endif
512
513 /* eventfd() */
514 #ifdef HAVE_SYS_EVENTFD_H
515 # include <sys/eventfd.h>
516 #endif
517
518 #ifdef _Py_MEMORY_SANITIZER
519 # include <sanitizer/msan_interface.h>
520 #endif
521
522 #ifdef HAVE_FORK
523 static void
524 344 run_at_forkers(PyObject *lst, int reverse)
525 {
526 Py_ssize_t i;
527 PyObject *cpy;
528
529
1/2
✓ Branch 0 taken 344 times.
✗ Branch 1 not taken.
344 if (lst != NULL) {
530 assert(PyList_CheckExact(lst));
531
532 /* Use a list copy in case register_at_fork() is called from
533 * one of the callbacks.
534 */
535 344 cpy = PyList_GetSlice(lst, 0, PyList_GET_SIZE(lst));
536
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 344 times.
344 if (cpy == NULL)
537 PyErr_WriteUnraisable(lst);
538 else {
539
2/2
✓ Branch 0 taken 172 times.
✓ Branch 1 taken 172 times.
344 if (reverse)
540 172 PyList_Reverse(cpy);
541
2/2
✓ Branch 1 taken 688 times.
✓ Branch 2 taken 344 times.
1032 for (i = 0; i < PyList_GET_SIZE(cpy); i++) {
542 PyObject *func, *res;
543 688 func = PyList_GET_ITEM(cpy, i);
544 688 res = _PyObject_CallNoArgs(func);
545
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 688 times.
688 if (res == NULL)
546 PyErr_WriteUnraisable(func);
547 else
548 688 Py_DECREF(res);
549 }
550 344 Py_DECREF(cpy);
551 }
552 }
553 344 }
554
555 void
556 172 PyOS_BeforeFork(void)
557 {
558 172 run_at_forkers(_PyInterpreterState_GET()->before_forkers, 1);
559
560 172 _PyImport_AcquireLock();
561 172 }
562
563 void
564 172 PyOS_AfterFork_Parent(void)
565 {
566
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 172 times.
172 if (_PyImport_ReleaseLock() <= 0)
567 Py_FatalError("failed releasing import lock after fork");
568
569 172 run_at_forkers(_PyInterpreterState_GET()->after_forkers_parent, 0);
570 172 }
571
572 void
573 PyOS_AfterFork_Child(void)
574 {
575 PyStatus status;
576 _PyRuntimeState *runtime = &_PyRuntime;
577
578 status = _PyGILState_Reinit(runtime);
579 if (_PyStatus_EXCEPTION(status)) {
580 goto fatal_error;
581 }
582
583 PyThreadState *tstate = _PyThreadState_GET();
584 _Py_EnsureTstateNotNULL(tstate);
585
586 status = _PyEval_ReInitThreads(tstate);
587 if (_PyStatus_EXCEPTION(status)) {
588 goto fatal_error;
589 }
590
591 status = _PyImport_ReInitLock();
592 if (_PyStatus_EXCEPTION(status)) {
593 goto fatal_error;
594 }
595
596 _PySignal_AfterFork();
597
598 status = _PyRuntimeState_ReInitThreads(runtime);
599 if (_PyStatus_EXCEPTION(status)) {
600 goto fatal_error;
601 }
602
603 status = _PyInterpreterState_DeleteExceptMain(runtime);
604 if (_PyStatus_EXCEPTION(status)) {
605 goto fatal_error;
606 }
607 assert(_PyThreadState_GET() == tstate);
608
609 run_at_forkers(tstate->interp->after_forkers_child, 0);
610 return;
611
612 fatal_error:
613 Py_ExitStatusException(status);
614 }
615
616 static int
617 14742 register_at_forker(PyObject **lst, PyObject *func)
618 {
619
2/2
✓ Branch 0 taken 8544 times.
✓ Branch 1 taken 6198 times.
14742 if (func == NULL) /* nothing to register? do nothing. */
620 8544 return 0;
621
2/2
✓ Branch 0 taken 3647 times.
✓ Branch 1 taken 2551 times.
6198 if (*lst == NULL) {
622 3647 *lst = PyList_New(0);
623
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3647 times.
3647 if (*lst == NULL)
624 return -1;
625 }
626 6198 return PyList_Append(*lst, func);
627 }
628 #endif /* HAVE_FORK */
629
630
631 /* Legacy wrapper */
632 void
633 PyOS_AfterFork(void)
634 {
635 #ifdef HAVE_FORK
636 PyOS_AfterFork_Child();
637 #endif
638 }
639
640
641 #ifdef MS_WINDOWS
642 /* defined in fileutils.c */
643 void _Py_time_t_to_FILE_TIME(time_t, int, FILETIME *);
644 void _Py_attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *,
645 ULONG, struct _Py_stat_struct *);
646 #endif
647
648
649 #ifndef MS_WINDOWS
650 PyObject *
651 2322123 _PyLong_FromUid(uid_t uid)
652 {
653
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2322123 times.
2322123 if (uid == (uid_t)-1)
654 return PyLong_FromLong(-1);
655 2322123 return PyLong_FromUnsignedLong(uid);
656 }
657
658 PyObject *
659 2321893 _PyLong_FromGid(gid_t gid)
660 {
661
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2321893 times.
2321893 if (gid == (gid_t)-1)
662 return PyLong_FromLong(-1);
663 2321893 return PyLong_FromUnsignedLong(gid);
664 }
665
666 int
667 _Py_Uid_Converter(PyObject *obj, uid_t *p)
668 {
669 uid_t uid;
670 PyObject *index;
671 int overflow;
672 long result;
673 unsigned long uresult;
674
675 index = _PyNumber_Index(obj);
676 if (index == NULL) {
677 PyErr_Format(PyExc_TypeError,
678 "uid should be integer, not %.200s",
679 _PyType_Name(Py_TYPE(obj)));
680 return 0;
681 }
682
683 /*
684 * Handling uid_t is complicated for two reasons:
685 * * Although uid_t is (always?) unsigned, it still
686 * accepts -1.
687 * * We don't know its size in advance--it may be
688 * bigger than an int, or it may be smaller than
689 * a long.
690 *
691 * So a bit of defensive programming is in order.
692 * Start with interpreting the value passed
693 * in as a signed long and see if it works.
694 */
695
696 result = PyLong_AsLongAndOverflow(index, &overflow);
697
698 if (!overflow) {
699 uid = (uid_t)result;
700
701 if (result == -1) {
702 if (PyErr_Occurred())
703 goto fail;
704 /* It's a legitimate -1, we're done. */
705 goto success;
706 }
707
708 /* Any other negative number is disallowed. */
709 if (result < 0)
710 goto underflow;
711
712 /* Ensure the value wasn't truncated. */
713 if (sizeof(uid_t) < sizeof(long) &&
714 (long)uid != result)
715 goto underflow;
716 goto success;
717 }
718
719 if (overflow < 0)
720 goto underflow;
721
722 /*
723 * Okay, the value overflowed a signed long. If it
724 * fits in an *unsigned* long, it may still be okay,
725 * as uid_t may be unsigned long on this platform.
726 */
727 uresult = PyLong_AsUnsignedLong(index);
728 if (PyErr_Occurred()) {
729 if (PyErr_ExceptionMatches(PyExc_OverflowError))
730 goto overflow;
731 goto fail;
732 }
733
734 uid = (uid_t)uresult;
735
736 /*
737 * If uid == (uid_t)-1, the user actually passed in ULONG_MAX,
738 * but this value would get interpreted as (uid_t)-1 by chown
739 * and its siblings. That's not what the user meant! So we
740 * throw an overflow exception instead. (We already
741 * handled a real -1 with PyLong_AsLongAndOverflow() above.)
742 */
743 if (uid == (uid_t)-1)
744 goto overflow;
745
746 /* Ensure the value wasn't truncated. */
747 if (sizeof(uid_t) < sizeof(long) &&
748 (unsigned long)uid != uresult)
749 goto overflow;
750 /* fallthrough */
751
752 success:
753 Py_DECREF(index);
754 *p = uid;
755 return 1;
756
757 underflow:
758 PyErr_SetString(PyExc_OverflowError,
759 "uid is less than minimum");
760 goto fail;
761
762 overflow:
763 PyErr_SetString(PyExc_OverflowError,
764 "uid is greater than maximum");
765 /* fallthrough */
766
767 fail:
768 Py_DECREF(index);
769 return 0;
770 }
771
772 int
773 _Py_Gid_Converter(PyObject *obj, gid_t *p)
774 {
775 gid_t gid;
776 PyObject *index;
777 int overflow;
778 long result;
779 unsigned long uresult;
780
781 index = _PyNumber_Index(obj);
782 if (index == NULL) {
783 PyErr_Format(PyExc_TypeError,
784 "gid should be integer, not %.200s",
785 _PyType_Name(Py_TYPE(obj)));
786 return 0;
787 }
788
789 /*
790 * Handling gid_t is complicated for two reasons:
791 * * Although gid_t is (always?) unsigned, it still
792 * accepts -1.
793 * * We don't know its size in advance--it may be
794 * bigger than an int, or it may be smaller than
795 * a long.
796 *
797 * So a bit of defensive programming is in order.
798 * Start with interpreting the value passed
799 * in as a signed long and see if it works.
800 */
801
802 result = PyLong_AsLongAndOverflow(index, &overflow);
803
804 if (!overflow) {
805 gid = (gid_t)result;
806
807 if (result == -1) {
808 if (PyErr_Occurred())
809 goto fail;
810 /* It's a legitimate -1, we're done. */
811 goto success;
812 }
813
814 /* Any other negative number is disallowed. */
815 if (result < 0) {
816 goto underflow;
817 }
818
819 /* Ensure the value wasn't truncated. */
820 if (sizeof(gid_t) < sizeof(long) &&
821 (long)gid != result)
822 goto underflow;
823 goto success;
824 }
825
826 if (overflow < 0)
827 goto underflow;
828
829 /*
830 * Okay, the value overflowed a signed long. If it
831 * fits in an *unsigned* long, it may still be okay,
832 * as gid_t may be unsigned long on this platform.
833 */
834 uresult = PyLong_AsUnsignedLong(index);
835 if (PyErr_Occurred()) {
836 if (PyErr_ExceptionMatches(PyExc_OverflowError))
837 goto overflow;
838 goto fail;
839 }
840
841 gid = (gid_t)uresult;
842
843 /*
844 * If gid == (gid_t)-1, the user actually passed in ULONG_MAX,
845 * but this value would get interpreted as (gid_t)-1 by chown
846 * and its siblings. That's not what the user meant! So we
847 * throw an overflow exception instead. (We already
848 * handled a real -1 with PyLong_AsLongAndOverflow() above.)
849 */
850 if (gid == (gid_t)-1)
851 goto overflow;
852
853 /* Ensure the value wasn't truncated. */
854 if (sizeof(gid_t) < sizeof(long) &&
855 (unsigned long)gid != uresult)
856 goto overflow;
857 /* fallthrough */
858
859 success:
860 Py_DECREF(index);
861 *p = gid;
862 return 1;
863
864 underflow:
865 PyErr_SetString(PyExc_OverflowError,
866 "gid is less than minimum");
867 goto fail;
868
869 overflow:
870 PyErr_SetString(PyExc_OverflowError,
871 "gid is greater than maximum");
872 /* fallthrough */
873
874 fail:
875 Py_DECREF(index);
876 return 0;
877 }
878 #endif /* MS_WINDOWS */
879
880
881 #define _PyLong_FromDev PyLong_FromLongLong
882
883
884 #if (defined(HAVE_MKNOD) && defined(HAVE_MAKEDEV)) || defined(HAVE_DEVICE_MACROS)
885 static int
886 _Py_Dev_Converter(PyObject *obj, void *p)
887 {
888 *((dev_t *)p) = PyLong_AsUnsignedLongLong(obj);
889 if (PyErr_Occurred())
890 return 0;
891 return 1;
892 }
893 #endif /* (HAVE_MKNOD && HAVE_MAKEDEV) || HAVE_DEVICE_MACROS */
894
895
896 #ifdef AT_FDCWD
897 /*
898 * Why the (int) cast? Solaris 10 defines AT_FDCWD as 0xffd19553 (-3041965);
899 * without the int cast, the value gets interpreted as uint (4291925331),
900 * which doesn't play nicely with all the initializer lines in this file that
901 * look like this:
902 * int dir_fd = DEFAULT_DIR_FD;
903 */
904 #define DEFAULT_DIR_FD (int)AT_FDCWD
905 #else
906 #define DEFAULT_DIR_FD (-100)
907 #endif
908
909 static int
910 50524 _fd_converter(PyObject *o, int *p)
911 {
912 int overflow;
913 long long_value;
914
915 50524 PyObject *index = _PyNumber_Index(o);
916
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50524 times.
50524 if (index == NULL) {
917 return 0;
918 }
919
920 assert(PyLong_Check(index));
921 50524 long_value = PyLong_AsLongAndOverflow(index, &overflow);
922 50524 Py_DECREF(index);
923 assert(!PyErr_Occurred());
924
2/4
✓ Branch 0 taken 50524 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 50524 times.
50524 if (overflow > 0 || long_value > INT_MAX) {
925 PyErr_SetString(PyExc_OverflowError,
926 "fd is greater than maximum");
927 return 0;
928 }
929
2/4
✓ Branch 0 taken 50524 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 50524 times.
50524 if (overflow < 0 || long_value < INT_MIN) {
930 PyErr_SetString(PyExc_OverflowError,
931 "fd is less than minimum");
932 return 0;
933 }
934
935 50524 *p = (int)long_value;
936 50524 return 1;
937 }
938
939 static int
940 57732 dir_fd_converter(PyObject *o, void *p)
941 {
942
2/2
✓ Branch 0 taken 8476 times.
✓ Branch 1 taken 49256 times.
57732 if (o == Py_None) {
943 8476 *(int *)p = DEFAULT_DIR_FD;
944 8476 return 1;
945 }
946
1/2
✓ Branch 1 taken 49256 times.
✗ Branch 2 not taken.
49256 else if (PyIndex_Check(o)) {
947 49256 return _fd_converter(o, (int *)p);
948 }
949 else {
950 PyErr_Format(PyExc_TypeError,
951 "argument should be integer or None, not %.200s",
952 _PyType_Name(Py_TYPE(o)));
953 return 0;
954 }
955 }
956
957 typedef struct {
958 PyObject *billion;
959 PyObject *DirEntryType;
960 PyObject *ScandirIteratorType;
961 #if defined(HAVE_SCHED_SETPARAM) || defined(HAVE_SCHED_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDPARAM)
962 PyObject *SchedParamType;
963 #endif
964 PyObject *StatResultType;
965 PyObject *StatVFSResultType;
966 PyObject *TerminalSizeType;
967 PyObject *TimesResultType;
968 PyObject *UnameResultType;
969 #if defined(HAVE_WAITID) && !defined(__APPLE__)
970 PyObject *WaitidResultType;
971 #endif
972 #if defined(HAVE_WAIT3) || defined(HAVE_WAIT4)
973 PyObject *struct_rusage;
974 #endif
975 PyObject *st_mode;
976 } _posixstate;
977
978
979 static inline _posixstate*
980 9783722 get_posix_state(PyObject *module)
981 {
982 9783722 void *state = _PyModule_GetState(module);
983 assert(state != NULL);
984 9783722 return (_posixstate *)state;
985 }
986
987 /*
988 * A PyArg_ParseTuple "converter" function
989 * that handles filesystem paths in the manner
990 * preferred by the os module.
991 *
992 * path_converter accepts (Unicode) strings and their
993 * subclasses, and bytes and their subclasses. What
994 * it does with the argument depends on the platform:
995 *
996 * * On Windows, if we get a (Unicode) string we
997 * extract the wchar_t * and return it; if we get
998 * bytes we decode to wchar_t * and return that.
999 *
1000 * * On all other platforms, strings are encoded
1001 * to bytes using PyUnicode_FSConverter, then we
1002 * extract the char * from the bytes object and
1003 * return that.
1004 *
1005 * path_converter also optionally accepts signed
1006 * integers (representing open file descriptors) instead
1007 * of path strings.
1008 *
1009 * Input fields:
1010 * path.nullable
1011 * If nonzero, the path is permitted to be None.
1012 * path.allow_fd
1013 * If nonzero, the path is permitted to be a file handle
1014 * (a signed int) instead of a string.
1015 * path.function_name
1016 * If non-NULL, path_converter will use that as the name
1017 * of the function in error messages.
1018 * (If path.function_name is NULL it omits the function name.)
1019 * path.argument_name
1020 * If non-NULL, path_converter will use that as the name
1021 * of the parameter in error messages.
1022 * (If path.argument_name is NULL it uses "path".)
1023 *
1024 * Output fields:
1025 * path.wide
1026 * Points to the path if it was expressed as Unicode
1027 * and was not encoded. (Only used on Windows.)
1028 * path.narrow
1029 * Points to the path if it was expressed as bytes,
1030 * or it was Unicode and was encoded to bytes. (On Windows,
1031 * is a non-zero integer if the path was expressed as bytes.
1032 * The type is deliberately incompatible to prevent misuse.)
1033 * path.fd
1034 * Contains a file descriptor if path.accept_fd was true
1035 * and the caller provided a signed integer instead of any
1036 * sort of string.
1037 *
1038 * WARNING: if your "path" parameter is optional, and is
1039 * unspecified, path_converter will never get called.
1040 * So if you set allow_fd, you *MUST* initialize path.fd = -1
1041 * yourself!
1042 * path.length
1043 * The length of the path in characters, if specified as
1044 * a string.
1045 * path.object
1046 * The original object passed in (if get a PathLike object,
1047 * the result of PyOS_FSPath() is treated as the original object).
1048 * Own a reference to the object.
1049 * path.cleanup
1050 * For internal use only. May point to a temporary object.
1051 * (Pay no attention to the man behind the curtain.)
1052 *
1053 * At most one of path.wide or path.narrow will be non-NULL.
1054 * If path was None and path.nullable was set,
1055 * or if path was an integer and path.allow_fd was set,
1056 * both path.wide and path.narrow will be NULL
1057 * and path.length will be 0.
1058 *
1059 * path_converter takes care to not write to the path_t
1060 * unless it's successful. However it must reset the
1061 * "cleanup" field each time it's called.
1062 *
1063 * Use as follows:
1064 * path_t path;
1065 * memset(&path, 0, sizeof(path));
1066 * PyArg_ParseTuple(args, "O&", path_converter, &path);
1067 * // ... use values from path ...
1068 * path_cleanup(&path);
1069 *
1070 * (Note that if PyArg_Parse fails you don't need to call
1071 * path_cleanup(). However it is safe to do so.)
1072 */
1073 typedef struct {
1074 const char *function_name;
1075 const char *argument_name;
1076 int nullable;
1077 int allow_fd;
1078 const wchar_t *wide;
1079 #ifdef MS_WINDOWS
1080 BOOL narrow;
1081 #else
1082 const char *narrow;
1083 #endif
1084 int fd;
1085 Py_ssize_t length;
1086 PyObject *object;
1087 PyObject *cleanup;
1088 } path_t;
1089
1090 #ifdef MS_WINDOWS
1091 #define PATH_T_INITIALIZE(function_name, argument_name, nullable, allow_fd) \
1092 {function_name, argument_name, nullable, allow_fd, NULL, FALSE, -1, 0, NULL, NULL}
1093 #else
1094 #define PATH_T_INITIALIZE(function_name, argument_name, nullable, allow_fd) \
1095 {function_name, argument_name, nullable, allow_fd, NULL, NULL, -1, 0, NULL, NULL}
1096 #endif
1097
1098 static void
1099 2736713 path_cleanup(path_t *path)
1100 {
1101 2736713 wchar_t *wide = (wchar_t *)path->wide;
1102 2736713 path->wide = NULL;
1103 2736713 PyMem_Free(wide);
1104
2/2
✓ Branch 0 taken 2734241 times.
✓ Branch 1 taken 2472 times.
2736713 Py_CLEAR(path->object);
1105
2/2
✓ Branch 0 taken 2732969 times.
✓ Branch 1 taken 3744 times.
2736713 Py_CLEAR(path->cleanup);
1106 2736713 }
1107
1108 static int
1109 2734241 path_converter(PyObject *o, void *p)
1110 {
1111 2734241 path_t *path = (path_t *)p;
1112 2734241 PyObject *bytes = NULL;
1113 2734241 Py_ssize_t length = 0;
1114 int is_index, is_buffer, is_bytes, is_unicode;
1115 const char *narrow;
1116 #ifdef MS_WINDOWS
1117 PyObject *wo = NULL;
1118 wchar_t *wide = NULL;
1119 #endif
1120
1121 #define FORMAT_EXCEPTION(exc, fmt) \
1122 PyErr_Format(exc, "%s%s" fmt, \
1123 path->function_name ? path->function_name : "", \
1124 path->function_name ? ": " : "", \
1125 path->argument_name ? path->argument_name : "path")
1126
1127 /* Py_CLEANUP_SUPPORTED support */
1128
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2734241 times.
2734241 if (o == NULL) {
1129 path_cleanup(path);
1130 return 1;
1131 }
1132
1133 /* Ensure it's always safe to call path_cleanup(). */
1134 2734241 path->object = path->cleanup = NULL;
1135 /* path->object owns a reference to the original object */
1136 2734241 Py_INCREF(o);
1137
1138
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2734241 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2734241 if ((o == Py_None) && path->nullable) {
1139 path->wide = NULL;
1140 #ifdef MS_WINDOWS
1141 path->narrow = FALSE;
1142 #else
1143 path->narrow = NULL;
1144 #endif
1145 path->fd = -1;
1146 goto success_exit;
1147 }
1148
1149 /* Only call this here so that we don't treat the return value of
1150 os.fspath() as an fd or buffer. */
1151
4/4
✓ Branch 0 taken 2524534 times.
✓ Branch 1 taken 209707 times.
✓ Branch 3 taken 1268 times.
✓ Branch 4 taken 2523266 times.
2734241 is_index = path->allow_fd && PyIndex_Check(o);
1152 2734241 is_buffer = PyObject_CheckBuffer(o);
1153 2734241 is_bytes = PyBytes_Check(o);
1154 2734241 is_unicode = PyUnicode_Check(o);
1155
1156
7/8
✓ Branch 0 taken 2732973 times.
✓ Branch 1 taken 1268 times.
✓ Branch 2 taken 2732969 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 588627 times.
✓ Branch 5 taken 2144342 times.
✓ Branch 6 taken 588627 times.
✗ Branch 7 not taken.
2734241 if (!is_index && !is_buffer && !is_unicode && !is_bytes) {
1157 /* Inline PyOS_FSPath() for better error messages. */
1158 PyObject *func, *res;
1159
1160 588627 func = _PyObject_LookupSpecial(o, &_Py_ID(__fspath__));
1161
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 588627 times.
588627 if (NULL == func) {
1162 goto error_format;
1163 }
1164 588627 res = _PyObject_CallNoArgs(func);
1165 588627 Py_DECREF(func);
1166
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 588627 times.
588627 if (NULL == res) {
1167 goto error_exit;
1168 }
1169
1/2
✓ Branch 2 taken 588627 times.
✗ Branch 3 not taken.
588627 else if (PyUnicode_Check(res)) {
1170 588627 is_unicode = 1;
1171 }
1172 else if (PyBytes_Check(res)) {
1173 is_bytes = 1;
1174 }
1175 else {
1176 PyErr_Format(PyExc_TypeError,
1177 "expected %.200s.__fspath__() to return str or bytes, "
1178 "not %.200s", _PyType_Name(Py_TYPE(o)),
1179 _PyType_Name(Py_TYPE(res)));
1180 Py_DECREF(res);
1181 goto error_exit;
1182 }
1183
1184 /* still owns a reference to the original object */
1185 588627 Py_DECREF(o);
1186 588627 o = res;
1187 }
1188
1189
2/2
✓ Branch 0 taken 2732969 times.
✓ Branch 1 taken 1272 times.
2734241 if (is_unicode) {
1190 #ifdef MS_WINDOWS
1191 wide = PyUnicode_AsWideCharString(o, &length);
1192 if (!wide) {
1193 goto error_exit;
1194 }
1195 if (length > 32767) {
1196 FORMAT_EXCEPTION(PyExc_ValueError, "%s too long for Windows");
1197 goto error_exit;
1198 }
1199 if (wcslen(wide) != length) {
1200 FORMAT_EXCEPTION(PyExc_ValueError, "embedded null character in %s");
1201 goto error_exit;
1202 }
1203
1204 path->wide = wide;
1205 path->narrow = FALSE;
1206 path->fd = -1;
1207 wide = NULL;
1208 goto success_exit;
1209 #else
1210
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2732969 times.
2732969 if (!PyUnicode_FSConverter(o, &bytes)) {
1211 goto error_exit;
1212 }
1213 #endif
1214 }
1215
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1268 times.
1272 else if (is_bytes) {
1216 4 bytes = o;
1217 4 Py_INCREF(bytes);
1218 }
1219
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1268 times.
1268 else if (is_buffer) {
1220 /* XXX Replace PyObject_CheckBuffer with PyBytes_Check in other code
1221 after removing support of non-bytes buffer objects. */
1222 if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
1223 "%s%s%s should be %s, not %.200s",
1224 path->function_name ? path->function_name : "",
1225 path->function_name ? ": " : "",
1226 path->argument_name ? path->argument_name : "path",
1227 path->allow_fd && path->nullable ? "string, bytes, os.PathLike, "
1228 "integer or None" :
1229 path->allow_fd ? "string, bytes, os.PathLike or integer" :
1230 path->nullable ? "string, bytes, os.PathLike or None" :
1231 "string, bytes or os.PathLike",
1232 _PyType_Name(Py_TYPE(o)))) {
1233 goto error_exit;
1234 }
1235 bytes = PyBytes_FromObject(o);
1236 if (!bytes) {
1237 goto error_exit;
1238 }
1239 }
1240
1/2
✓ Branch 0 taken 1268 times.
✗ Branch 1 not taken.
1268 else if (is_index) {
1241
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1268 times.
1268 if (!_fd_converter(o, &path->fd)) {
1242 goto error_exit;
1243 }
1244 1268 path->wide = NULL;
1245 #ifdef MS_WINDOWS
1246 path->narrow = FALSE;
1247 #else
1248 1268 path->narrow = NULL;
1249 #endif
1250 1268 goto success_exit;
1251 }
1252 else {
1253 error_format:
1254 PyErr_Format(PyExc_TypeError, "%s%s%s should be %s, not %.200s",
1255 path->function_name ? path->function_name : "",
1256 path->function_name ? ": " : "",
1257 path->argument_name ? path->argument_name : "path",
1258 path->allow_fd && path->nullable ? "string, bytes, os.PathLike, "
1259 "integer or None" :
1260 path->allow_fd ? "string, bytes, os.PathLike or integer" :
1261 path->nullable ? "string, bytes, os.PathLike or None" :
1262 "string, bytes or os.PathLike",
1263 _PyType_Name(Py_TYPE(o)));
1264 goto error_exit;
1265 }
1266
1267 2732973 length = PyBytes_GET_SIZE(bytes);
1268 2732973 narrow = PyBytes_AS_STRING(bytes);
1269
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2732973 times.
2732973 if ((size_t)length != strlen(narrow)) {
1270 FORMAT_EXCEPTION(PyExc_ValueError, "embedded null character in %s");
1271 goto error_exit;
1272 }
1273
1274 #ifdef MS_WINDOWS
1275 wo = PyUnicode_DecodeFSDefaultAndSize(
1276 narrow,
1277 length
1278 );
1279 if (!wo) {
1280 goto error_exit;
1281 }
1282
1283 wide = PyUnicode_AsWideCharString(wo, &length);
1284 Py_DECREF(wo);
1285 if (!wide) {
1286 goto error_exit;
1287 }
1288 if (length > 32767) {
1289 FORMAT_EXCEPTION(PyExc_ValueError, "%s too long for Windows");
1290 goto error_exit;
1291 }
1292 if (wcslen(wide) != length) {
1293 FORMAT_EXCEPTION(PyExc_ValueError, "embedded null character in %s");
1294 goto error_exit;
1295 }
1296 path->wide = wide;
1297 path->narrow = TRUE;
1298 Py_DECREF(bytes);
1299 wide = NULL;
1300 #else
1301 2732973 path->wide = NULL;
1302 2732973 path->narrow = narrow;
1303
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2732969 times.
2732973 if (bytes == o) {
1304 /* Still a reference owned by path->object, don't have to
1305 worry about path->narrow is used after free. */
1306 4 Py_DECREF(bytes);
1307 }
1308 else {
1309 2732969 path->cleanup = bytes;
1310 }
1311 #endif
1312 2732973 path->fd = -1;
1313
1314 2734241 success_exit:
1315 2734241 path->length = length;
1316 2734241 path->object = o;
1317 2734241 return Py_CLEANUP_SUPPORTED;
1318
1319 error_exit:
1320 Py_XDECREF(o);
1321 Py_XDECREF(bytes);
1322 #ifdef MS_WINDOWS
1323 PyMem_Free(wide);
1324 #endif
1325 return 0;
1326 }
1327
1328 static void
1329 argument_unavailable_error(const char *function_name, const char *argument_name)
1330 {
1331 PyErr_Format(PyExc_NotImplementedError,
1332 "%s%s%s unavailable on this platform",
1333 (function_name != NULL) ? function_name : "",
1334 (function_name != NULL) ? ": ": "",
1335 argument_name);
1336 }
1337
1338 static int
1339 3404 dir_fd_unavailable(PyObject *o, void *p)
1340 {
1341 int dir_fd;
1342
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (!dir_fd_converter(o, &dir_fd))
1343 return 0;
1344
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3404 times.
3404 if (dir_fd != DEFAULT_DIR_FD) {
1345 argument_unavailable_error(NULL, "dir_fd");
1346 return 0;
1347 }
1348 3404 *(int *)p = dir_fd;
1349 3404 return 1;
1350 }
1351
1352 static int
1353 3404 fd_specified(const char *function_name, int fd)
1354 {
1355
1/2
✓ Branch 0 taken 3404 times.
✗ Branch 1 not taken.
3404 if (fd == -1)
1356 3404 return 0;
1357
1358 argument_unavailable_error(function_name, "fd");
1359 return 1;
1360 }
1361
1362 static int
1363 3404 follow_symlinks_specified(const char *function_name, int follow_symlinks)
1364 {
1365
1/2
✓ Branch 0 taken 3404 times.
✗ Branch 1 not taken.
3404 if (follow_symlinks)
1366 3404 return 0;
1367
1368 argument_unavailable_error(function_name, "follow_symlinks");
1369 return 1;
1370 }
1371
1372 static int
1373 2533453 path_and_dir_fd_invalid(const char *function_name, path_t *path, int dir_fd)
1374 {
1375
2/4
✓ Branch 0 taken 2533453 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2533453 times.
2533453 if (!path->wide && (dir_fd != DEFAULT_DIR_FD)
1376 #ifndef MS_WINDOWS
1377 && !path->narrow
1378 #endif
1379 ) {
1380 PyErr_Format(PyExc_ValueError,
1381 "%s: can't specify dir_fd without matching path",
1382 function_name);
1383 return 1;
1384 }
1385 2533453 return 0;
1386 }
1387
1388 static int
1389 2533453 dir_fd_and_fd_invalid(const char *function_name, int dir_fd, int fd)
1390 {
1391
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2533453 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2533453 if ((dir_fd != DEFAULT_DIR_FD) && (fd != -1)) {
1392 PyErr_Format(PyExc_ValueError,
1393 "%s: can't specify both dir_fd and fd",
1394 function_name);
1395 return 1;
1396 }
1397 2533453 return 0;
1398 }
1399
1400 static int
1401 2533520 fd_and_follow_symlinks_invalid(const char *function_name, int fd,
1402 int follow_symlinks)
1403 {
1404
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2533520 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2533520 if ((fd > 0) && (!follow_symlinks)) {
1405 PyErr_Format(PyExc_ValueError,
1406 "%s: cannot use fd and follow_symlinks together",
1407 function_name);
1408 return 1;
1409 }
1410 2533520 return 0;
1411 }
1412
1413 static int
1414 3404 dir_fd_and_follow_symlinks_invalid(const char *function_name, int dir_fd,
1415 int follow_symlinks)
1416 {
1417
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3404 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
3404 if ((dir_fd != DEFAULT_DIR_FD) && (!follow_symlinks)) {
1418 PyErr_Format(PyExc_ValueError,
1419 "%s: cannot use dir_fd and follow_symlinks together",
1420 function_name);
1421 return 1;
1422 }
1423 3404 return 0;
1424 }
1425
1426 #ifdef MS_WINDOWS
1427 typedef long long Py_off_t;
1428 #else
1429 typedef off_t Py_off_t;
1430 #endif
1431
1432 static int
1433 140 Py_off_t_converter(PyObject *arg, void *addr)
1434 {
1435 #ifdef HAVE_LARGEFILE_SUPPORT
1436 *((Py_off_t *)addr) = PyLong_AsLongLong(arg);
1437 #else
1438 140 *((Py_off_t *)addr) = PyLong_AsLong(arg);
1439 #endif
1440
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 140 times.
140 if (PyErr_Occurred())
1441 return 0;
1442 140 return 1;
1443 }
1444
1445 static PyObject *
1446 PyLong_FromPy_off_t(Py_off_t offset)
1447 {
1448 #ifdef HAVE_LARGEFILE_SUPPORT
1449 return PyLong_FromLongLong(offset);
1450 #else
1451 return PyLong_FromLong(offset);
1452 #endif
1453 }
1454
1455 #ifdef HAVE_SIGSET_T
1456 /* Convert an iterable of integers to a sigset.
1457 Return 1 on success, return 0 and raise an exception on error. */
1458 int
1459 _Py_Sigset_Converter(PyObject *obj, void *addr)
1460 {
1461 sigset_t *mask = (sigset_t *)addr;
1462 PyObject *iterator, *item;
1463 long signum;
1464 int overflow;
1465
1466 // The extra parens suppress the unreachable-code warning with clang on MacOS
1467 if (sigemptyset(mask) < (0)) {
1468 /* Probably only if mask == NULL. */
1469 PyErr_SetFromErrno(PyExc_OSError);
1470 return 0;
1471 }
1472
1473 iterator = PyObject_GetIter(obj);
1474 if (iterator == NULL) {
1475 return 0;
1476 }
1477
1478 while ((item = PyIter_Next(iterator)) != NULL) {
1479 signum = PyLong_AsLongAndOverflow(item, &overflow);
1480 Py_DECREF(item);
1481 if (signum <= 0 || signum >= Py_NSIG) {
1482 if (overflow || signum != -1 || !PyErr_Occurred()) {
1483 PyErr_Format(PyExc_ValueError,
1484 "signal number %ld out of range [1; %i]",
1485 signum, Py_NSIG - 1);
1486 }
1487 goto error;
1488 }
1489 if (sigaddset(mask, (int)signum)) {
1490 if (errno != EINVAL) {
1491 /* Probably impossible */
1492 PyErr_SetFromErrno(PyExc_OSError);
1493 goto error;
1494 }
1495 /* For backwards compatibility, allow idioms such as
1496 * `range(1, NSIG)` but warn about invalid signal numbers
1497 */
1498 const char msg[] =
1499 "invalid signal number %ld, please use valid_signals()";
1500 if (PyErr_WarnFormat(PyExc_RuntimeWarning, 1, msg, signum)) {
1501 goto error;
1502 }
1503 }
1504 }
1505 if (!PyErr_Occurred()) {
1506 Py_DECREF(iterator);
1507 return 1;
1508 }
1509
1510 error:
1511 Py_DECREF(iterator);
1512 return 0;
1513 }
1514 #endif /* HAVE_SIGSET_T */
1515
1516 #ifdef MS_WINDOWS
1517
1518 static int
1519 win32_get_reparse_tag(HANDLE reparse_point_handle, ULONG *reparse_tag)
1520 {
1521 char target_buffer[_Py_MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
1522 _Py_REPARSE_DATA_BUFFER *rdb = (_Py_REPARSE_DATA_BUFFER *)target_buffer;
1523 DWORD n_bytes_returned;
1524
1525 if (0 == DeviceIoControl(
1526 reparse_point_handle,
1527 FSCTL_GET_REPARSE_POINT,
1528 NULL, 0, /* in buffer */
1529 target_buffer, sizeof(target_buffer),
1530 &n_bytes_returned,
1531 NULL)) /* we're not using OVERLAPPED_IO */
1532 return FALSE;
1533
1534 if (reparse_tag)
1535 *reparse_tag = rdb->ReparseTag;
1536
1537 return TRUE;
1538 }
1539
1540 #endif /* MS_WINDOWS */
1541
1542 /* Return a dictionary corresponding to the POSIX environment table */
1543 #if defined(WITH_NEXT_FRAMEWORK) || (defined(__APPLE__) && defined(Py_ENABLE_SHARED))
1544 /* On Darwin/MacOSX a shared library or framework has no access to
1545 ** environ directly, we must obtain it with _NSGetEnviron(). See also
1546 ** man environ(7).
1547 */
1548 #include <crt_externs.h>
1549 #elif !defined(_MSC_VER) && (!defined(__WATCOMC__) || defined(__QNX__) || defined(__VXWORKS__))
1550 extern char **environ;
1551 #endif /* !_MSC_VER */
1552
1553 static PyObject *
1554 3404 convertenviron(void)
1555 {
1556 PyObject *d;
1557 #ifdef MS_WINDOWS
1558 wchar_t **e;
1559 #else
1560 char **e;
1561 #endif
1562
1563 3404 d = PyDict_New();
1564
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3404 times.
3404 if (d == NULL)
1565 return NULL;
1566 #ifdef MS_WINDOWS
1567 /* _wenviron must be initialized in this way if the program is started
1568 through main() instead of wmain(). */
1569 _wgetenv(L"");
1570 e = _wenviron;
1571 #elif defined(WITH_NEXT_FRAMEWORK) || (defined(__APPLE__) && defined(Py_ENABLE_SHARED))
1572 /* environ is not accessible as an extern in a shared object on OSX; use
1573 _NSGetEnviron to resolve it. The value changes if you add environment
1574 variables between calls to Py_Initialize, so don't cache the value. */
1575 e = *_NSGetEnviron();
1576 #else
1577 3404 e = environ;
1578 #endif
1579
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3404 times.
3404 if (e == NULL)
1580 return d;
1581
2/2
✓ Branch 0 taken 18179 times.
✓ Branch 1 taken 3404 times.
21583 for (; *e != NULL; e++) {
1582 PyObject *k;
1583 PyObject *v;
1584 #ifdef MS_WINDOWS
1585 const wchar_t *p = wcschr(*e, L'=');
1586 #else
1587 18179 const char *p = strchr(*e, '=');
1588 #endif
1589
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18179 times.
18179 if (p == NULL)
1590 continue;
1591 #ifdef MS_WINDOWS
1592 k = PyUnicode_FromWideChar(*e, (Py_ssize_t)(p-*e));
1593 #else
1594 18179 k = PyBytes_FromStringAndSize(*e, (int)(p-*e));
1595 #endif
1596
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18179 times.
18179 if (k == NULL) {
1597 Py_DECREF(d);
1598 return NULL;
1599 }
1600 #ifdef MS_WINDOWS
1601 v = PyUnicode_FromWideChar(p+1, wcslen(p+1));
1602 #else
1603 18179 v = PyBytes_FromStringAndSize(p+1, strlen(p+1));
1604 #endif
1605
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18179 times.
18179 if (v == NULL) {
1606 Py_DECREF(k);
1607 Py_DECREF(d);
1608 return NULL;
1609 }
1610
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 18179 times.
18179 if (PyDict_SetDefault(d, k, v) == NULL) {
1611 Py_DECREF(v);
1612 Py_DECREF(k);
1613 Py_DECREF(d);
1614 return NULL;
1615 }
1616 18179 Py_DECREF(k);
1617 18179 Py_DECREF(v);
1618 }
1619 3404 return d;
1620 }
1621
1622 /* Set a POSIX-specific error from errno, and return NULL */
1623
1624 static PyObject *
1625 posix_error(void)
1626 {
1627 return PyErr_SetFromErrno(PyExc_OSError);
1628 }
1629
1630 #ifdef MS_WINDOWS
1631 static PyObject *
1632 win32_error(const char* function, const char* filename)
1633 {
1634 /* XXX We should pass the function name along in the future.
1635 (winreg.c also wants to pass the function name.)
1636 This would however require an additional param to the
1637 Windows error object, which is non-trivial.
1638 */
1639 errno = GetLastError();
1640 if (filename)
1641 return PyErr_SetFromWindowsErrWithFilename(errno, filename);
1642 else
1643 return PyErr_SetFromWindowsErr(errno);
1644 }
1645
1646 static PyObject *
1647 win32_error_object_err(const char* function, PyObject* filename, DWORD err)
1648 {
1649 /* XXX - see win32_error for comments on 'function' */
1650 if (filename)
1651 return PyErr_SetExcFromWindowsErrWithFilenameObject(
1652 PyExc_OSError,
1653 err,
1654 filename);
1655 else
1656 return PyErr_SetFromWindowsErr(err);
1657 }
1658
1659 static PyObject *
1660 win32_error_object(const char* function, PyObject* filename)
1661 {
1662 errno = GetLastError();
1663 return win32_error_object_err(function, filename, errno);
1664 }
1665
1666 #endif /* MS_WINDOWS */
1667
1668 static PyObject *
1669 252305 posix_path_object_error(PyObject *path)
1670 {
1671 252305 return PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path);
1672 }
1673
1674 static PyObject *
1675 252305 path_object_error(PyObject *path)
1676 {
1677 #ifdef MS_WINDOWS
1678 return PyErr_SetExcFromWindowsErrWithFilenameObject(
1679 PyExc_OSError, 0, path);
1680 #else
1681 252305 return posix_path_object_error(path);
1682 #endif
1683 }
1684
1685 static PyObject *
1686 path_object_error2(PyObject *path, PyObject *path2)
1687 {
1688 #ifdef MS_WINDOWS
1689 return PyErr_SetExcFromWindowsErrWithFilenameObjects(
1690 PyExc_OSError, 0, path, path2);
1691 #else
1692 return PyErr_SetFromErrnoWithFilenameObjects(PyExc_OSError, path, path2);
1693 #endif
1694 }
1695
1696 static PyObject *
1697 252305 path_error(path_t *path)
1698 {
1699 252305 return path_object_error(path->object);
1700 }
1701
1702 static PyObject *
1703 posix_path_error(path_t *path)
1704 {
1705 return posix_path_object_error(path->object);
1706 }
1707
1708 static PyObject *
1709 path_error2(path_t *path, path_t *path2)
1710 {
1711 return path_object_error2(path->object, path2->object);
1712 }
1713
1714
1715 /* POSIX generic methods */
1716
1717 static PyObject *
1718 81 posix_fildes_fd(int fd, int (*func)(int))
1719 {
1720 int res;
1721 81 int async_err = 0;
1722
1723 do {
1724 81 Py_BEGIN_ALLOW_THREADS
1725 _Py_BEGIN_SUPPRESS_IPH
1726 81 res = (*func)(fd);
1727 _Py_END_SUPPRESS_IPH
1728 81 Py_END_ALLOW_THREADS
1729
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 81 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
81 } while (res != 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
1730
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 81 times.
81 if (res != 0)
1731 return (!async_err) ? posix_error() : NULL;
1732 81 Py_RETURN_NONE;
1733 }
1734
1735
1736 #ifdef MS_WINDOWS
1737 /* This is a reimplementation of the C library's chdir function,
1738 but one that produces Win32 errors instead of DOS error codes.
1739 chdir is essentially a wrapper around SetCurrentDirectory; however,
1740 it also needs to set "magic" environment variables indicating
1741 the per-drive current directory, which are of the form =<drive>: */
1742 static BOOL __stdcall
1743 win32_wchdir(LPCWSTR path)
1744 {
1745 wchar_t path_buf[MAX_PATH], *new_path = path_buf;
1746 int result;
1747 wchar_t env[4] = L"=x:";
1748
1749 if(!SetCurrentDirectoryW(path))
1750 return FALSE;
1751 result = GetCurrentDirectoryW(Py_ARRAY_LENGTH(path_buf), new_path);
1752 if (!result)
1753 return FALSE;
1754 if (result > Py_ARRAY_LENGTH(path_buf)) {
1755 new_path = PyMem_RawMalloc(result * sizeof(wchar_t));
1756 if (!new_path) {
1757 SetLastError(ERROR_OUTOFMEMORY);
1758 return FALSE;
1759 }
1760 result = GetCurrentDirectoryW(result, new_path);
1761 if (!result) {
1762 PyMem_RawFree(new_path);
1763 return FALSE;
1764 }
1765 }
1766 int is_unc_like_path = (wcsncmp(new_path, L"\\\\", 2) == 0 ||
1767 wcsncmp(new_path, L"//", 2) == 0);
1768 if (!is_unc_like_path) {
1769 env[1] = new_path[0];
1770 result = SetEnvironmentVariableW(env, new_path);
1771 }
1772 if (new_path != path_buf)
1773 PyMem_RawFree(new_path);
1774 return result ? TRUE : FALSE;
1775 }
1776 #endif
1777
1778 #ifdef MS_WINDOWS
1779 /* The CRT of Windows has a number of flaws wrt. its stat() implementation:
1780 - time stamps are restricted to second resolution
1781 - file modification times suffer from forth-and-back conversions between
1782 UTC and local time
1783 Therefore, we implement our own stat, based on the Win32 API directly.
1784 */
1785 #define HAVE_STAT_NSEC 1
1786 #define HAVE_STRUCT_STAT_ST_FILE_ATTRIBUTES 1
1787 #define HAVE_STRUCT_STAT_ST_REPARSE_TAG 1
1788
1789 static void
1790 find_data_to_file_info(WIN32_FIND_DATAW *pFileData,
1791 BY_HANDLE_FILE_INFORMATION *info,
1792 ULONG *reparse_tag)
1793 {
1794 memset(info, 0, sizeof(*info));
1795 info->dwFileAttributes = pFileData->dwFileAttributes;
1796 info->ftCreationTime = pFileData->ftCreationTime;
1797 info->ftLastAccessTime = pFileData->ftLastAccessTime;
1798 info->ftLastWriteTime = pFileData->ftLastWriteTime;
1799 info->nFileSizeHigh = pFileData->nFileSizeHigh;
1800 info->nFileSizeLow = pFileData->nFileSizeLow;
1801 /* info->nNumberOfLinks = 1; */
1802 if (pFileData->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
1803 *reparse_tag = pFileData->dwReserved0;
1804 else
1805 *reparse_tag = 0;
1806 }
1807
1808 static BOOL
1809 attributes_from_dir(LPCWSTR pszFile, BY_HANDLE_FILE_INFORMATION *info, ULONG *reparse_tag)
1810 {
1811 HANDLE hFindFile;
1812 WIN32_FIND_DATAW FileData;
1813 LPCWSTR filename = pszFile;
1814 size_t n = wcslen(pszFile);
1815 if (n && (pszFile[n - 1] == L'\\' || pszFile[n - 1] == L'/')) {
1816 // cannot use PyMem_Malloc here because we do not hold the GIL
1817 filename = (LPCWSTR)malloc((n + 1) * sizeof(filename[0]));
1818 wcsncpy_s((LPWSTR)filename, n + 1, pszFile, n);
1819 while (--n > 0 && (filename[n] == L'\\' || filename[n] == L'/')) {
1820 ((LPWSTR)filename)[n] = L'\0';
1821 }
1822 if (!n || (n == 1 && filename[1] == L':')) {
1823 // Nothing left to query
1824 free((void *)filename);
1825 return FALSE;
1826 }
1827 }
1828 hFindFile = FindFirstFileW(filename, &FileData);
1829 if (pszFile != filename) {
1830 free((void *)filename);
1831 }
1832 if (hFindFile == INVALID_HANDLE_VALUE) {
1833 return FALSE;
1834 }
1835 FindClose(hFindFile);
1836 find_data_to_file_info(&FileData, info, reparse_tag);
1837 return TRUE;
1838 }
1839
1840 static int
1841 win32_xstat_impl(const wchar_t *path, struct _Py_stat_struct *result,
1842 BOOL traverse)
1843 {
1844 HANDLE hFile;
1845 BY_HANDLE_FILE_INFORMATION fileInfo;
1846 FILE_ATTRIBUTE_TAG_INFO tagInfo = { 0 };
1847 DWORD fileType, error;
1848 BOOL isUnhandledTag = FALSE;
1849 int retval = 0;
1850
1851 DWORD access = FILE_READ_ATTRIBUTES;
1852 DWORD flags = FILE_FLAG_BACKUP_SEMANTICS; /* Allow opening directories. */
1853 if (!traverse) {
1854 flags |= FILE_FLAG_OPEN_REPARSE_POINT;
1855 }
1856
1857 hFile = CreateFileW(path, access, 0, NULL, OPEN_EXISTING, flags, NULL);
1858 if (hFile == INVALID_HANDLE_VALUE) {
1859 /* Either the path doesn't exist, or the caller lacks access. */
1860 error = GetLastError();
1861 switch (error) {
1862 case ERROR_ACCESS_DENIED: /* Cannot sync or read attributes. */
1863 case ERROR_SHARING_VIOLATION: /* It's a paging file. */
1864 /* Try reading the parent directory. */
1865 if (!attributes_from_dir(path, &fileInfo, &tagInfo.ReparseTag)) {
1866 /* Cannot read the parent directory. */
1867 switch (GetLastError()) {
1868 case ERROR_FILE_NOT_FOUND: /* File cannot be found */
1869 case ERROR_PATH_NOT_FOUND: /* File parent directory cannot be found */
1870 case ERROR_NOT_READY: /* Drive exists but unavailable */
1871 case ERROR_BAD_NET_NAME: /* Remote drive unavailable */
1872 break;
1873 /* Restore the error from CreateFileW(). */
1874 default:
1875 SetLastError(error);
1876 }
1877
1878 return -1;
1879 }
1880 if (fileInfo.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
1881 if (traverse ||
1882 !IsReparseTagNameSurrogate(tagInfo.ReparseTag)) {
1883 /* The stat call has to traverse but cannot, so fail. */
1884 SetLastError(error);
1885 return -1;
1886 }
1887 }
1888 break;
1889
1890 case ERROR_INVALID_PARAMETER:
1891 /* \\.\con requires read or write access. */
1892 hFile = CreateFileW(path, access | GENERIC_READ,
1893 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1894 OPEN_EXISTING, flags, NULL);
1895 if (hFile == INVALID_HANDLE_VALUE) {
1896 SetLastError(error);
1897 return -1;
1898 }
1899 break;
1900
1901 case ERROR_CANT_ACCESS_FILE:
1902 /* bpo37834: open unhandled reparse points if traverse fails. */
1903 if (traverse) {
1904 traverse = FALSE;
1905 isUnhandledTag = TRUE;
1906 hFile = CreateFileW(path, access, 0, NULL, OPEN_EXISTING,
1907 flags | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
1908 }
1909 if (hFile == INVALID_HANDLE_VALUE) {
1910 SetLastError(error);
1911 return -1;
1912 }
1913 break;
1914
1915 default:
1916 return -1;
1917 }
1918 }
1919
1920 if (hFile != INVALID_HANDLE_VALUE) {
1921 /* Handle types other than files on disk. */
1922 fileType = GetFileType(hFile);
1923 if (fileType != FILE_TYPE_DISK) {
1924 if (fileType == FILE_TYPE_UNKNOWN && GetLastError() != 0) {
1925 retval = -1;
1926 goto cleanup;
1927 }
1928 DWORD fileAttributes = GetFileAttributesW(path);
1929 memset(result, 0, sizeof(*result));
1930 if (fileAttributes != INVALID_FILE_ATTRIBUTES &&
1931 fileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
1932 /* \\.\pipe\ or \\.\mailslot\ */
1933 result->st_mode = _S_IFDIR;
1934 } else if (fileType == FILE_TYPE_CHAR) {
1935 /* \\.\nul */
1936 result->st_mode = _S_IFCHR;
1937 } else if (fileType == FILE_TYPE_PIPE) {
1938 /* \\.\pipe\spam */
1939 result->st_mode = _S_IFIFO;
1940 }
1941 /* FILE_TYPE_UNKNOWN, e.g. \\.\mailslot\waitfor.exe\spam */
1942 goto cleanup;
1943 }
1944
1945 /* Query the reparse tag, and traverse a non-link. */
1946 if (!traverse) {
1947 if (!GetFileInformationByHandleEx(hFile, FileAttributeTagInfo,
1948 &tagInfo, sizeof(tagInfo))) {
1949 /* Allow devices that do not support FileAttributeTagInfo. */
1950 switch (GetLastError()) {
1951 case ERROR_INVALID_PARAMETER:
1952 case ERROR_INVALID_FUNCTION:
1953 case ERROR_NOT_SUPPORTED:
1954 tagInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
1955 tagInfo.ReparseTag = 0;
1956 break;
1957 default:
1958 retval = -1;
1959 goto cleanup;
1960 }
1961 } else if (tagInfo.FileAttributes &
1962 FILE_ATTRIBUTE_REPARSE_POINT) {
1963 if (IsReparseTagNameSurrogate(tagInfo.ReparseTag)) {
1964 if (isUnhandledTag) {
1965 /* Traversing previously failed for either this link
1966 or its target. */
1967 SetLastError(ERROR_CANT_ACCESS_FILE);
1968 retval = -1;
1969 goto cleanup;
1970 }
1971 /* Traverse a non-link, but not if traversing already failed
1972 for an unhandled tag. */
1973 } else if (!isUnhandledTag) {
1974 CloseHandle(hFile);
1975 return win32_xstat_impl(path, result, TRUE);
1976 }
1977 }
1978 }
1979
1980 if (!GetFileInformationByHandle(hFile, &fileInfo)) {
1981 switch (GetLastError()) {
1982 case ERROR_INVALID_PARAMETER:
1983 case ERROR_INVALID_FUNCTION:
1984 case ERROR_NOT_SUPPORTED:
1985 /* Volumes and physical disks are block devices, e.g.
1986 \\.\C: and \\.\PhysicalDrive0. */
1987 memset(result, 0, sizeof(*result));
1988 result->st_mode = 0x6000; /* S_IFBLK */
1989 goto cleanup;
1990 }
1991 retval = -1;
1992 goto cleanup;
1993 }
1994 }
1995
1996 _Py_attribute_data_to_stat(&fileInfo, tagInfo.ReparseTag, result);
1997
1998 if (!(fileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
1999 /* Fix the file execute permissions. This hack sets S_IEXEC if
2000 the filename has an extension that is commonly used by files
2001 that CreateProcessW can execute. A real implementation calls
2002 GetSecurityInfo, OpenThreadToken/OpenProcessToken, and
2003 AccessCheck to check for generic read, write, and execute
2004 access. */
2005 const wchar_t *fileExtension = wcsrchr(path, '.');
2006 if (fileExtension) {
2007 if (_wcsicmp(fileExtension, L".exe") == 0 ||
2008 _wcsicmp(fileExtension, L".bat") == 0 ||
2009 _wcsicmp(fileExtension, L".cmd") == 0 ||
2010 _wcsicmp(fileExtension, L".com") == 0) {
2011 result->st_mode |= 0111;
2012 }
2013 }
2014 }
2015
2016 cleanup:
2017 if (hFile != INVALID_HANDLE_VALUE) {
2018 /* Preserve last error if we are failing */
2019 error = retval ? GetLastError() : 0;
2020 if (!CloseHandle(hFile)) {
2021 retval = -1;
2022 } else if (retval) {
2023 /* Restore last error */
2024 SetLastError(error);
2025 }
2026 }
2027
2028 return retval;
2029 }
2030
2031 static int
2032 win32_xstat(const wchar_t *path, struct _Py_stat_struct *result, BOOL traverse)
2033 {
2034 /* Protocol violation: we explicitly clear errno, instead of
2035 setting it to a POSIX error. Callers should use GetLastError. */
2036 int code = win32_xstat_impl(path, result, traverse);
2037 errno = 0;
2038 return code;
2039 }
2040 /* About the following functions: win32_lstat_w, win32_stat, win32_stat_w
2041
2042 In Posix, stat automatically traverses symlinks and returns the stat
2043 structure for the target. In Windows, the equivalent GetFileAttributes by
2044 default does not traverse symlinks and instead returns attributes for
2045 the symlink.
2046
2047 Instead, we will open the file (which *does* traverse symlinks by default)
2048 and GetFileInformationByHandle(). */
2049
2050 static int
2051 win32_lstat(const wchar_t* path, struct _Py_stat_struct *result)
2052 {
2053 return win32_xstat(path, result, FALSE);
2054 }
2055
2056 static int
2057 win32_stat(const wchar_t* path, struct _Py_stat_struct *result)
2058 {
2059 return win32_xstat(path, result, TRUE);
2060 }
2061
2062 #endif /* MS_WINDOWS */
2063
2064 PyDoc_STRVAR(stat_result__doc__,
2065 "stat_result: Result from stat, fstat, or lstat.\n\n\
2066 This object may be accessed either as a tuple of\n\
2067 (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime)\n\
2068 or via the attributes st_mode, st_ino, st_dev, st_nlink, st_uid, and so on.\n\
2069 \n\
2070 Posix/windows: If your platform supports st_blksize, st_blocks, st_rdev,\n\
2071 or st_flags, they are available as attributes only.\n\
2072 \n\
2073 See os.stat for more information.");
2074
2075 static PyStructSequence_Field stat_result_fields[] = {
2076 {"st_mode", "protection bits"},
2077 {"st_ino", "inode"},
2078 {"st_dev", "device"},
2079 {"st_nlink", "number of hard links"},
2080 {"st_uid", "user ID of owner"},
2081 {"st_gid", "group ID of owner"},
2082 {"st_size", "total size, in bytes"},
2083 /* The NULL is replaced with PyStructSequence_UnnamedField later. */
2084 {NULL, "integer time of last access"},
2085 {NULL, "integer time of last modification"},
2086 {NULL, "integer time of last change"},
2087 {"st_atime", "time of last access"},
2088 {"st_mtime", "time of last modification"},
2089 {"st_ctime", "time of last change"},
2090 {"st_atime_ns", "time of last access in nanoseconds"},
2091 {"st_mtime_ns", "time of last modification in nanoseconds"},
2092 {"st_ctime_ns", "time of last change in nanoseconds"},
2093 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
2094 {"st_blksize", "blocksize for filesystem I/O"},
2095 #endif
2096 #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
2097 {"st_blocks", "number of blocks allocated"},
2098 #endif
2099 #ifdef HAVE_STRUCT_STAT_ST_RDEV
2100 {"st_rdev", "device type (if inode device)"},
2101 #endif
2102 #ifdef HAVE_STRUCT_STAT_ST_FLAGS
2103 {"st_flags", "user defined flags for file"},
2104 #endif
2105 #ifdef HAVE_STRUCT_STAT_ST_GEN
2106 {"st_gen", "generation number"},
2107 #endif
2108 #ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME
2109 {"st_birthtime", "time of creation"},
2110 #endif
2111 #ifdef HAVE_STRUCT_STAT_ST_FILE_ATTRIBUTES
2112 {"st_file_attributes", "Windows file attribute bits"},
2113 #endif
2114 #ifdef HAVE_STRUCT_STAT_ST_FSTYPE
2115 {"st_fstype", "Type of filesystem"},
2116 #endif
2117 #ifdef HAVE_STRUCT_STAT_ST_REPARSE_TAG
2118 {"st_reparse_tag", "Windows reparse tag"},
2119 #endif
2120 {0}
2121 };
2122
2123 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
2124 #define ST_BLKSIZE_IDX 16
2125 #else
2126 #define ST_BLKSIZE_IDX 15
2127 #endif
2128
2129 #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
2130 #define ST_BLOCKS_IDX (ST_BLKSIZE_IDX+1)
2131 #else
2132 #define ST_BLOCKS_IDX ST_BLKSIZE_IDX
2133 #endif
2134
2135 #ifdef HAVE_STRUCT_STAT_ST_RDEV
2136 #define ST_RDEV_IDX (ST_BLOCKS_IDX+1)
2137 #else
2138 #define ST_RDEV_IDX ST_BLOCKS_IDX
2139 #endif
2140
2141 #ifdef HAVE_STRUCT_STAT_ST_FLAGS
2142 #define ST_FLAGS_IDX (ST_RDEV_IDX+1)
2143 #else
2144 #define ST_FLAGS_IDX ST_RDEV_IDX
2145 #endif
2146
2147 #ifdef HAVE_STRUCT_STAT_ST_GEN
2148 #define ST_GEN_IDX (ST_FLAGS_IDX+1)
2149 #else
2150 #define ST_GEN_IDX ST_FLAGS_IDX
2151 #endif
2152
2153 #ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME
2154 #define ST_BIRTHTIME_IDX (ST_GEN_IDX+1)
2155 #else
2156 #define ST_BIRTHTIME_IDX ST_GEN_IDX
2157 #endif
2158
2159 #ifdef HAVE_STRUCT_STAT_ST_FILE_ATTRIBUTES
2160 #define ST_FILE_ATTRIBUTES_IDX (ST_BIRTHTIME_IDX+1)
2161 #else
2162 #define ST_FILE_ATTRIBUTES_IDX ST_BIRTHTIME_IDX
2163 #endif
2164
2165 #ifdef HAVE_STRUCT_STAT_ST_FSTYPE
2166 #define ST_FSTYPE_IDX (ST_FILE_ATTRIBUTES_IDX+1)
2167 #else
2168 #define ST_FSTYPE_IDX ST_FILE_ATTRIBUTES_IDX
2169 #endif
2170
2171 #ifdef HAVE_STRUCT_STAT_ST_REPARSE_TAG
2172 #define ST_REPARSE_TAG_IDX (ST_FSTYPE_IDX+1)
2173 #else
2174 #define ST_REPARSE_TAG_IDX ST_FSTYPE_IDX
2175 #endif
2176
2177 static PyStructSequence_Desc stat_result_desc = {
2178 "stat_result", /* name */
2179 stat_result__doc__, /* doc */
2180 stat_result_fields,
2181 10
2182 };
2183
2184 PyDoc_STRVAR(statvfs_result__doc__,
2185 "statvfs_result: Result from statvfs or fstatvfs.\n\n\
2186 This object may be accessed either as a tuple of\n\
2187 (bsize, frsize, blocks, bfree, bavail, files, ffree, favail, flag, namemax),\n\
2188 or via the attributes f_bsize, f_frsize, f_blocks, f_bfree, and so on.\n\
2189 \n\
2190 See os.statvfs for more information.");
2191
2192 static PyStructSequence_Field statvfs_result_fields[] = {
2193 {"f_bsize", },
2194 {"f_frsize", },
2195 {"f_blocks", },
2196 {"f_bfree", },
2197 {"f_bavail", },
2198 {"f_files", },
2199 {"f_ffree", },
2200 {"f_favail", },
2201 {"f_flag", },
2202 {"f_namemax",},
2203 {"f_fsid", },
2204 {0}
2205 };
2206
2207 static PyStructSequence_Desc statvfs_result_desc = {
2208 "statvfs_result", /* name */
2209 statvfs_result__doc__, /* doc */
2210 statvfs_result_fields,
2211 10
2212 };
2213
2214 #if defined(HAVE_WAITID) && !defined(__APPLE__)
2215 PyDoc_STRVAR(waitid_result__doc__,
2216 "waitid_result: Result from waitid.\n\n\
2217 This object may be accessed either as a tuple of\n\
2218 (si_pid, si_uid, si_signo, si_status, si_code),\n\
2219 or via the attributes si_pid, si_uid, and so on.\n\
2220 \n\
2221 See os.waitid for more information.");
2222
2223 static PyStructSequence_Field waitid_result_fields[] = {
2224 {"si_pid", },
2225 {"si_uid", },
2226 {"si_signo", },
2227 {"si_status", },
2228 {"si_code", },
2229 {0}
2230 };
2231
2232 static PyStructSequence_Desc waitid_result_desc = {
2233 "waitid_result", /* name */
2234 waitid_result__doc__, /* doc */
2235 waitid_result_fields,
2236 5
2237 };
2238 #endif
2239 static newfunc structseq_new;
2240
2241 static PyObject *
2242 statresult_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
2243 {
2244 PyStructSequence *result;
2245 int i;
2246
2247 result = (PyStructSequence*)structseq_new(type, args, kwds);
2248 if (!result)
2249 return NULL;
2250 /* If we have been initialized from a tuple,
2251 st_?time might be set to None. Initialize it
2252 from the int slots. */
2253 for (i = 7; i <= 9; i++) {
2254 if (result->ob_item[i+3] == Py_None) {
2255 Py_DECREF(Py_None);
2256 Py_INCREF(result->ob_item[i]);
2257 result->ob_item[i+3] = result->ob_item[i];
2258 }
2259 }
2260 return (PyObject*)result;
2261 }
2262
2263 static int
2264 6808 _posix_clear(PyObject *module)
2265 {
2266 6808 _posixstate *state = get_posix_state(module);
2267
2/2
✓ Branch 0 taken 3404 times.
✓ Branch 1 taken 3404 times.
6808 Py_CLEAR(state->billion);
2268
2/2
✓ Branch 0 taken 3404 times.
✓ Branch 1 taken 3404 times.
6808 Py_CLEAR(state->DirEntryType);
2269
2/2
✓ Branch 0 taken 3404 times.
✓ Branch 1 taken 3404 times.
6808 Py_CLEAR(state->ScandirIteratorType);
2270 #if defined(HAVE_SCHED_SETPARAM) || defined(HAVE_SCHED_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDPARAM)
2271
2/2
✓ Branch 0 taken 3404 times.
✓ Branch 1 taken 3404 times.
6808 Py_CLEAR(state->SchedParamType);
2272 #endif
2273
2/2
✓ Branch 0 taken 3404 times.
✓ Branch 1 taken 3404 times.
6808 Py_CLEAR(state->StatResultType);
2274
2/2
✓ Branch 0 taken 3404 times.
✓ Branch 1 taken 3404 times.
6808 Py_CLEAR(state->StatVFSResultType);
2275
2/2
✓ Branch 0 taken 3404 times.
✓ Branch 1 taken 3404 times.
6808 Py_CLEAR(state->TerminalSizeType);
2276
2/2
✓ Branch 0 taken 3404 times.
✓ Branch 1 taken 3404 times.
6808 Py_CLEAR(state->TimesResultType);
2277
2/2
✓ Branch 0 taken 3404 times.
✓ Branch 1 taken 3404 times.
6808 Py_CLEAR(state->UnameResultType);
2278 #if defined(HAVE_WAITID) && !defined(__APPLE__)
2279
2/2
✓ Branch 0 taken 3404 times.
✓ Branch 1 taken 3404 times.
6808 Py_CLEAR(state->WaitidResultType);
2280 #endif
2281 #if defined(HAVE_WAIT3) || defined(HAVE_WAIT4)
2282
2/2
✓ Branch 0 taken 3404 times.
✓ Branch 1 taken 3404 times.
6808 Py_CLEAR(state->struct_rusage);
2283 #endif
2284
2/2
✓ Branch 0 taken 3404 times.
✓ Branch 1 taken 3404 times.
6808 Py_CLEAR(state->st_mode);
2285 6808 return 0;
2286 }
2287
2288 static int
2289 34896 _posix_traverse(PyObject *module, visitproc visit, void *arg)
2290 {
2291 34896 _posixstate *state = get_posix_state(module);
2292
3/4
✓ Branch 0 taken 34854 times.
✓ Branch 1 taken 42 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 34854 times.
34896 Py_VISIT(state->billion);
2293
3/4
✓ Branch 0 taken 34854 times.
✓ Branch 1 taken 42 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 34854 times.
34896 Py_VISIT(state->DirEntryType);
2294
3/4
✓ Branch 0 taken 34854 times.
✓ Branch 1 taken 42 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 34854 times.
34896 Py_VISIT(state->ScandirIteratorType);
2295 #if defined(HAVE_SCHED_SETPARAM) || defined(HAVE_SCHED_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDPARAM)
2296
3/4
✓ Branch 0 taken 34854 times.
✓ Branch 1 taken 42 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 34854 times.
34896 Py_VISIT(state->SchedParamType);
2297 #endif
2298
2/4
✓ Branch 0 taken 34896 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 34896 times.
34896 Py_VISIT(state->StatResultType);
2299
2/4
✓ Branch 0 taken 34896 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 34896 times.
34896 Py_VISIT(state->StatVFSResultType);
2300
3/4
✓ Branch 0 taken 34854 times.
✓ Branch 1 taken 42 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 34854 times.
34896 Py_VISIT(state->TerminalSizeType);
2301
3/4
✓ Branch 0 taken 34854 times.
✓ Branch 1 taken 42 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 34854 times.
34896 Py_VISIT(state->TimesResultType);
2302
3/4
✓ Branch 0 taken 34854 times.
✓ Branch 1 taken 42 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 34854 times.
34896 Py_VISIT(state->UnameResultType);
2303 #if defined(HAVE_WAITID) && !defined(__APPLE__)
2304
2/4
✓ Branch 0 taken 34896 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 34896 times.
34896 Py_VISIT(state->WaitidResultType);
2305 #endif
2306 #if defined(HAVE_WAIT3) || defined(HAVE_WAIT4)
2307
3/4
✓ Branch 0 taken 34854 times.
✓ Branch 1 taken 42 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 34854 times.
34896 Py_VISIT(state->struct_rusage);
2308 #endif
2309
3/4
✓ Branch 0 taken 34854 times.
✓ Branch 1 taken 42 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 34854 times.
34896 Py_VISIT(state->st_mode);
2310 34896 return 0;
2311 }
2312
2313 static void
2314 3404 _posix_free(void *module)
2315 {
2316 3404 _posix_clear((PyObject *)module);
2317 3404 }
2318
2319 static void
2320 6965655 fill_time(PyObject *module, PyObject *v, int index, time_t sec, unsigned long nsec)
2321 {
2322 6965655 PyObject *s = _PyLong_FromTime_t(sec);
2323 6965655 PyObject *ns_fractional = PyLong_FromUnsignedLong(nsec);
2324 6965655 PyObject *s_in_ns = NULL;
2325 6965655 PyObject *ns_total = NULL;
2326 6965655 PyObject *float_s = NULL;
2327
2328
2/4
✓ Branch 0 taken 6965655 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6965655 times.
6965655 if (!(s && ns_fractional))
2329 goto exit;
2330
2331 6965655 s_in_ns = PyNumber_Multiply(s, get_posix_state(module)->billion);
2332
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6965655 times.
6965655 if (!s_in_ns)
2333 goto exit;
2334
2335 6965655 ns_total = PyNumber_Add(s_in_ns, ns_fractional);
2336
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6965655 times.
6965655 if (!ns_total)
2337 goto exit;
2338
2339 6965655 float_s = PyFloat_FromDouble(sec + 1e-9*nsec);
2340
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6965655 times.
6965655 if (!float_s) {
2341 goto exit;
2342 }
2343
2344 6965655 PyStructSequence_SET_ITEM(v, index, s);
2345 6965655 PyStructSequence_SET_ITEM(v, index+3, float_s);
2346 6965655 PyStructSequence_SET_ITEM(v, index+6, ns_total);
2347 6965655 s = NULL;
2348 6965655 float_s = NULL;
2349 6965655 ns_total = NULL;
2350 6965655 exit:
2351 6965655 Py_XDECREF(s);
2352 6965655 Py_XDECREF(ns_fractional);
2353 6965655 Py_XDECREF(s_in_ns);
2354 6965655 Py_XDECREF(ns_total);
2355 6965655 Py_XDECREF(float_s);
2356 6965655 }
2357
2358 /* pack a system stat C structure into the Python stat tuple
2359 (used by posix_stat() and posix_fstat()) */
2360 static PyObject*
2361 2321885 _pystat_fromstructstat(PyObject *module, STRUCT_STAT *st)
2362 {
2363 unsigned long ansec, mnsec, cnsec;
2364 2321885 PyObject *StatResultType = get_posix_state(module)->StatResultType;
2365 2321885 PyObject *v = PyStructSequence_New((PyTypeObject *)StatResultType);
2366
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2321885 times.
2321885 if (v == NULL)
2367 return NULL;
2368
2369 2321885 PyStructSequence_SET_ITEM(v, 0, PyLong_FromLong((long)st->st_mode));
2370 static_assert(sizeof(unsigned long long) >= sizeof(st->st_ino),
2371 "stat.st_ino is larger than unsigned long long");
2372 2321885 PyStructSequence_SET_ITEM(v, 1, PyLong_FromUnsignedLongLong(st->st_ino));
2373 #ifdef MS_WINDOWS
2374 PyStructSequence_SET_ITEM(v, 2, PyLong_FromUnsignedLong(st->st_dev));
2375 #else
2376 2321885 PyStructSequence_SET_ITEM(v, 2, _PyLong_FromDev(st->st_dev));
2377 #endif
2378 2321885 PyStructSequence_SET_ITEM(v, 3, PyLong_FromLong((long)st->st_nlink));
2379 #if defined(MS_WINDOWS)
2380 PyStructSequence_SET_ITEM(v, 4, PyLong_FromLong(0));
2381 PyStructSequence_SET_ITEM(v, 5, PyLong_FromLong(0));
2382 #else
2383 2321885 PyStructSequence_SET_ITEM(v, 4, _PyLong_FromUid(st->st_uid));
2384 2321885 PyStructSequence_SET_ITEM(v, 5, _PyLong_FromGid(st->st_gid));
2385 #endif
2386 static_assert(sizeof(long long) >= sizeof(st->st_size),
2387 "stat.st_size is larger than long long");
2388 2321885 PyStructSequence_SET_ITEM(v, 6, PyLong_FromLongLong(st->st_size));
2389
2390 #if defined(HAVE_STAT_TV_NSEC)
2391 2321885 ansec = st->st_atim.tv_nsec;
2392 2321885 mnsec = st->st_mtim.tv_nsec;
2393 2321885 cnsec = st->st_ctim.tv_nsec;
2394 #elif defined(HAVE_STAT_TV_NSEC2)
2395 ansec = st->st_atimespec.tv_nsec;
2396 mnsec = st->st_mtimespec.tv_nsec;
2397 cnsec = st->st_ctimespec.tv_nsec;
2398 #elif defined(HAVE_STAT_NSEC)
2399 ansec = st->st_atime_nsec;
2400 mnsec = st->st_mtime_nsec;
2401 cnsec = st->st_ctime_nsec;
2402 #else
2403 ansec = mnsec = cnsec = 0;
2404 #endif
2405 2321885 fill_time(module, v, 7, st->st_atime, ansec);
2406 2321885 fill_time(module, v, 8, st->st_mtime, mnsec);
2407 2321885 fill_time(module, v, 9, st->st_ctime, cnsec);
2408
2409 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
2410 2321885 PyStructSequence_SET_ITEM(v, ST_BLKSIZE_IDX,
2411 PyLong_FromLong((long)st->st_blksize));
2412 #endif
2413 #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
2414 2321885 PyStructSequence_SET_ITEM(v, ST_BLOCKS_IDX,
2415 PyLong_FromLong((long)st->st_blocks));
2416 #endif
2417 #ifdef HAVE_STRUCT_STAT_ST_RDEV
2418 2321885 PyStructSequence_SET_ITEM(v, ST_RDEV_IDX,
2419 PyLong_FromLong((long)st->st_rdev));
2420 #endif
2421 #ifdef HAVE_STRUCT_STAT_ST_GEN
2422 PyStructSequence_SET_ITEM(v, ST_GEN_IDX,
2423 PyLong_FromLong((long)st->st_gen));
2424 #endif
2425 #ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME
2426 {
2427 PyObject *val;
2428 unsigned long bsec,bnsec;
2429 bsec = (long)st->st_birthtime;
2430 #ifdef HAVE_STAT_TV_NSEC2
2431 bnsec = st->st_birthtimespec.tv_nsec;
2432 #else
2433 bnsec = 0;
2434 #endif
2435 val = PyFloat_FromDouble(bsec + 1e-9*bnsec);
2436 PyStructSequence_SET_ITEM(v, ST_BIRTHTIME_IDX,
2437 val);
2438 }
2439 #endif
2440 #ifdef HAVE_STRUCT_STAT_ST_FLAGS
2441 PyStructSequence_SET_ITEM(v, ST_FLAGS_IDX,
2442 PyLong_FromLong((long)st->st_flags));
2443 #endif
2444 #ifdef HAVE_STRUCT_STAT_ST_FILE_ATTRIBUTES
2445 PyStructSequence_SET_ITEM(v, ST_FILE_ATTRIBUTES_IDX,
2446 PyLong_FromUnsignedLong(st->st_file_attributes));
2447 #endif
2448 #ifdef HAVE_STRUCT_STAT_ST_FSTYPE
2449 PyStructSequence_SET_ITEM(v, ST_FSTYPE_IDX,
2450 PyUnicode_FromString(st->st_fstype));
2451 #endif
2452 #ifdef HAVE_STRUCT_STAT_ST_REPARSE_TAG
2453 PyStructSequence_SET_ITEM(v, ST_REPARSE_TAG_IDX,
2454 PyLong_FromUnsignedLong(st->st_reparse_tag));
2455 #endif
2456
2457
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2321885 times.
2321885 if (PyErr_Occurred()) {
2458 Py_DECREF(v);
2459 return NULL;
2460 }
2461
2462 2321885 return v;
2463 }
2464
2465 /* POSIX methods */
2466
2467
2468 static PyObject *
2469 2530027 posix_do_stat(PyObject *module, const char *function_name, path_t *path,
2470 int dir_fd, int follow_symlinks)
2471 {
2472 STRUCT_STAT st;
2473 int result;
2474
2475 #ifdef HAVE_FSTATAT
2476 2530027 int fstatat_unavailable = 0;
2477 #endif
2478
2479 #if !defined(MS_WINDOWS) && !defined(HAVE_FSTATAT) && !defined(HAVE_LSTAT)
2480 if (follow_symlinks_specified(function_name, follow_symlinks))
2481 return NULL;
2482 #endif
2483
2484
2/4
✓ Branch 1 taken 2530027 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2530027 times.
✗ Branch 4 not taken.
5060054 if (path_and_dir_fd_invalid("stat", path, dir_fd) ||
2485
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2530027 times.
5060054 dir_fd_and_fd_invalid("stat", dir_fd, path->fd) ||
2486 2530027 fd_and_follow_symlinks_invalid("stat", path->fd, follow_symlinks))
2487 return NULL;
2488
2489 2530027 Py_BEGIN_ALLOW_THREADS
2490
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2530027 times.
2530027 if (path->fd != -1)
2491 result = FSTAT(path->fd, &st);
2492 #ifdef MS_WINDOWS
2493 else if (follow_symlinks)
2494 result = win32_stat(path->wide, &st);
2495 else
2496 result = win32_lstat(path->wide, &st);
2497 #else
2498 else
2499 #if defined(HAVE_LSTAT)
2500
3/4
✓ Branch 0 taken 120910 times.
✓ Branch 1 taken 2409117 times.
✓ Branch 2 taken 120910 times.
✗ Branch 3 not taken.
2530027 if ((!follow_symlinks) && (dir_fd == DEFAULT_DIR_FD))
2501 120910 result = LSTAT(path->narrow, &st);
2502 else
2503 #endif /* HAVE_LSTAT */
2504 #ifdef HAVE_FSTATAT
2505
2/4
✓ Branch 0 taken 2409117 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2409117 times.
2409117 if ((dir_fd != DEFAULT_DIR_FD) || !follow_symlinks) {
2506 if (HAVE_FSTATAT_RUNTIME) {
2507 result = fstatat(dir_fd, path->narrow, &st,
2508 follow_symlinks ? 0 : AT_SYMLINK_NOFOLLOW);
2509
2510 } else {
2511 fstatat_unavailable = 1;
2512 }
2513 } else
2514 #endif /* HAVE_FSTATAT */
2515 2409117 result = STAT(path->narrow, &st);
2516 #endif /* MS_WINDOWS */
2517 2530027 Py_END_ALLOW_THREADS
2518
2519 #ifdef HAVE_FSTATAT
2520
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2530027 times.
2530027 if (fstatat_unavailable) {
2521 argument_unavailable_error("stat", "dir_fd");
2522 return NULL;
2523 }
2524 #endif
2525
2526
2/2
✓ Branch 0 taken 210931 times.
✓ Branch 1 taken 2319096 times.
2530027 if (result != 0) {
2527 210931 return path_error(path);
2528 }
2529
2530 2319096 return _pystat_fromstructstat(module, &st);
2531 }
2532
2533 /*[python input]
2534
2535 for s in """
2536
2537 FACCESSAT
2538 FCHMODAT
2539 FCHOWNAT
2540 FSTATAT
2541 LINKAT
2542 MKDIRAT
2543 MKFIFOAT
2544 MKNODAT
2545 OPENAT
2546 READLINKAT
2547 SYMLINKAT
2548 UNLINKAT
2549
2550 """.strip().split():
2551 s = s.strip()
2552 print("""
2553 #ifdef HAVE_{s}
2554 #define {s}_DIR_FD_CONVERTER dir_fd_converter
2555 #else
2556 #define {s}_DIR_FD_CONVERTER dir_fd_unavailable
2557 #endif
2558 """.rstrip().format(s=s))
2559
2560 for s in """
2561
2562 FCHDIR
2563 FCHMOD
2564 FCHOWN
2565 FDOPENDIR
2566 FEXECVE
2567 FPATHCONF
2568 FSTATVFS
2569 FTRUNCATE
2570
2571 """.strip().split():
2572 s = s.strip()
2573 print("""
2574 #ifdef HAVE_{s}
2575 #define PATH_HAVE_{s} 1
2576 #else
2577 #define PATH_HAVE_{s} 0
2578 #endif
2579
2580 """.rstrip().format(s=s))
2581 [python start generated code]*/
2582
2583 #ifdef HAVE_FACCESSAT
2584 #define FACCESSAT_DIR_FD_CONVERTER dir_fd_converter
2585 #else
2586 #define FACCESSAT_DIR_FD_CONVERTER dir_fd_unavailable
2587 #endif
2588
2589 #ifdef HAVE_FCHMODAT
2590 #define FCHMODAT_DIR_FD_CONVERTER dir_fd_converter
2591 #else
2592 #define FCHMODAT_DIR_FD_CONVERTER dir_fd_unavailable
2593 #endif
2594
2595 #ifdef HAVE_FCHOWNAT
2596 #define FCHOWNAT_DIR_FD_CONVERTER dir_fd_converter
2597 #else
2598 #define FCHOWNAT_DIR_FD_CONVERTER dir_fd_unavailable
2599 #endif
2600
2601 #ifdef HAVE_FSTATAT
2602 #define FSTATAT_DIR_FD_CONVERTER dir_fd_converter
2603 #else
2604 #define FSTATAT_DIR_FD_CONVERTER dir_fd_unavailable
2605 #endif
2606
2607 #ifdef HAVE_LINKAT
2608 #define LINKAT_DIR_FD_CONVERTER dir_fd_converter
2609 #else
2610 #define LINKAT_DIR_FD_CONVERTER dir_fd_unavailable
2611 #endif
2612
2613 #ifdef HAVE_MKDIRAT
2614 #define MKDIRAT_DIR_FD_CONVERTER dir_fd_converter
2615 #else
2616 #define MKDIRAT_DIR_FD_CONVERTER dir_fd_unavailable
2617 #endif
2618
2619 #ifdef HAVE_MKFIFOAT
2620 #define MKFIFOAT_DIR_FD_CONVERTER dir_fd_converter
2621 #else
2622 #define MKFIFOAT_DIR_FD_CONVERTER dir_fd_unavailable
2623 #endif
2624
2625 #ifdef HAVE_MKNODAT
2626 #define MKNODAT_DIR_FD_CONVERTER dir_fd_converter
2627 #else
2628 #define MKNODAT_DIR_FD_CONVERTER dir_fd_unavailable
2629 #endif
2630
2631 #ifdef HAVE_OPENAT
2632 #define OPENAT_DIR_FD_CONVERTER dir_fd_converter
2633 #else
2634 #define OPENAT_DIR_FD_CONVERTER dir_fd_unavailable
2635 #endif
2636
2637 #ifdef HAVE_READLINKAT
2638 #define READLINKAT_DIR_FD_CONVERTER dir_fd_converter
2639 #else
2640 #define READLINKAT_DIR_FD_CONVERTER dir_fd_unavailable
2641 #endif
2642
2643 #ifdef HAVE_SYMLINKAT
2644 #define SYMLINKAT_DIR_FD_CONVERTER dir_fd_converter
2645 #else
2646 #define SYMLINKAT_DIR_FD_CONVERTER dir_fd_unavailable
2647 #endif
2648
2649 #ifdef HAVE_UNLINKAT
2650 #define UNLINKAT_DIR_FD_CONVERTER dir_fd_converter
2651 #else
2652 #define UNLINKAT_DIR_FD_CONVERTER dir_fd_unavailable
2653 #endif
2654
2655 #ifdef HAVE_FCHDIR
2656 #define PATH_HAVE_FCHDIR 1
2657 #else
2658 #define PATH_HAVE_FCHDIR 0
2659 #endif
2660
2661 #ifdef HAVE_FCHMOD
2662 #define PATH_HAVE_FCHMOD 1
2663 #else
2664 #define PATH_HAVE_FCHMOD 0
2665 #endif
2666
2667 #ifdef HAVE_FCHOWN
2668 #define PATH_HAVE_FCHOWN 1
2669 #else
2670 #define PATH_HAVE_FCHOWN 0
2671 #endif
2672
2673 #ifdef HAVE_FDOPENDIR
2674 #define PATH_HAVE_FDOPENDIR 1
2675 #else
2676 #define PATH_HAVE_FDOPENDIR 0
2677 #endif
2678
2679 #ifdef HAVE_FEXECVE
2680 #define PATH_HAVE_FEXECVE 1
2681 #else
2682 #define PATH_HAVE_FEXECVE 0
2683 #endif
2684
2685 #ifdef HAVE_FPATHCONF
2686 #define PATH_HAVE_FPATHCONF 1
2687 #else
2688 #define PATH_HAVE_FPATHCONF 0
2689 #endif
2690
2691 #ifdef HAVE_FSTATVFS
2692 #define PATH_HAVE_FSTATVFS 1
2693 #else
2694 #define PATH_HAVE_FSTATVFS 0
2695 #endif
2696
2697 #ifdef HAVE_FTRUNCATE
2698 #define PATH_HAVE_FTRUNCATE 1
2699 #else
2700 #define PATH_HAVE_FTRUNCATE 0
2701 #endif
2702 /*[python end generated code: output=4bd4f6f7d41267f1 input=80b4c890b6774ea5]*/
2703
2704 #ifdef MS_WINDOWS
2705 #undef PATH_HAVE_FTRUNCATE
2706 #define PATH_HAVE_FTRUNCATE 1
2707 #endif
2708
2709 /*[python input]
2710
2711 class path_t_converter(CConverter):
2712
2713 type = "path_t"
2714 impl_by_reference = True
2715 parse_by_reference = True
2716
2717 converter = 'path_converter'
2718
2719 def converter_init(self, *, allow_fd=False, nullable=False):
2720 # right now path_t doesn't support default values.
2721 # to support a default value, you'll need to override initialize().
2722 if self.default not in (unspecified, None):
2723 fail("Can't specify a default to the path_t converter!")
2724
2725 if self.c_default not in (None, 'Py_None'):
2726 raise RuntimeError("Can't specify a c_default to the path_t converter!")
2727
2728 self.nullable = nullable
2729 self.allow_fd = allow_fd
2730
2731 def pre_render(self):
2732 def strify(value):
2733 if isinstance(value, str):
2734 return value
2735 return str(int(bool(value)))
2736
2737 # add self.py_name here when merging with posixmodule conversion
2738 self.c_default = 'PATH_T_INITIALIZE("{}", "{}", {}, {})'.format(
2739 self.function.name,
2740 self.name,
2741 strify(self.nullable),
2742 strify(self.allow_fd),
2743 )
2744
2745 def cleanup(self):
2746 return "path_cleanup(&" + self.name + ");\n"
2747
2748
2749 class dir_fd_converter(CConverter):
2750 type = 'int'
2751
2752 def converter_init(self, requires=None):
2753 if self.default in (unspecified, None):
2754 self.c_default = 'DEFAULT_DIR_FD'
2755 if isinstance(requires, str):
2756 self.converter = requires.upper() + '_DIR_FD_CONVERTER'
2757 else:
2758 self.converter = 'dir_fd_converter'
2759
2760 class uid_t_converter(CConverter):
2761 type = "uid_t"
2762 converter = '_Py_Uid_Converter'
2763
2764 class gid_t_converter(CConverter):
2765 type = "gid_t"
2766 converter = '_Py_Gid_Converter'
2767
2768 class dev_t_converter(CConverter):
2769 type = 'dev_t'
2770 converter = '_Py_Dev_Converter'
2771
2772 class dev_t_return_converter(unsigned_long_return_converter):
2773 type = 'dev_t'
2774 conversion_fn = '_PyLong_FromDev'
2775 unsigned_cast = '(dev_t)'
2776
2777 class FSConverter_converter(CConverter):
2778 type = 'PyObject *'
2779 converter = 'PyUnicode_FSConverter'
2780 def converter_init(self):
2781 if self.default is not unspecified:
2782 fail("FSConverter_converter does not support default values")
2783 self.c_default = 'NULL'
2784
2785 def cleanup(self):
2786 return "Py_XDECREF(" + self.name + ");\n"
2787
2788 class pid_t_converter(CConverter):
2789 type = 'pid_t'
2790 format_unit = '" _Py_PARSE_PID "'
2791
2792 class idtype_t_converter(int_converter):
2793 type = 'idtype_t'
2794
2795 class id_t_converter(CConverter):
2796 type = 'id_t'
2797 format_unit = '" _Py_PARSE_PID "'
2798
2799 class intptr_t_converter(CConverter):
2800 type = 'intptr_t'
2801 format_unit = '" _Py_PARSE_INTPTR "'
2802
2803 class Py_off_t_converter(CConverter):
2804 type = 'Py_off_t'
2805 converter = 'Py_off_t_converter'
2806
2807 class Py_off_t_return_converter(long_return_converter):
2808 type = 'Py_off_t'
2809 conversion_fn = 'PyLong_FromPy_off_t'
2810
2811 class path_confname_converter(CConverter):
2812 type="int"
2813 converter="conv_path_confname"
2814
2815 class confstr_confname_converter(path_confname_converter):
2816 converter='conv_confstr_confname'
2817
2818 class sysconf_confname_converter(path_confname_converter):
2819 converter="conv_sysconf_confname"
2820
2821 [python start generated code]*/
2822 /*[python end generated code: output=da39a3ee5e6b4b0d input=3338733161aa7879]*/
2823
2824 /*[clinic input]
2825
2826 os.stat
2827
2828 path : path_t(allow_fd=True)
2829 Path to be examined; can be string, bytes, a path-like object or
2830 open-file-descriptor int.
2831
2832 *
2833
2834 dir_fd : dir_fd(requires='fstatat') = None
2835 If not None, it should be a file descriptor open to a directory,
2836 and path should be a relative string; path will then be relative to
2837 that directory.
2838
2839 follow_symlinks: bool = True
2840 If False, and the last element of the path is a symbolic link,
2841 stat will examine the symbolic link itself instead of the file
2842 the link points to.
2843
2844 Perform a stat system call on the given path.
2845
2846 dir_fd and follow_symlinks may not be implemented
2847 on your platform. If they are unavailable, using them will raise a
2848 NotImplementedError.
2849
2850 It's an error to use dir_fd or follow_symlinks when specifying path as
2851 an open file descriptor.
2852
2853 [clinic start generated code]*/
2854
2855 static PyObject *
2856 2409117 os_stat_impl(PyObject *module, path_t *path, int dir_fd, int follow_symlinks)
2857 /*[clinic end generated code: output=7d4976e6f18a59c5 input=01d362ebcc06996b]*/
2858 {
2859 2409117 return posix_do_stat(module, "stat", path, dir_fd, follow_symlinks);
2860 }
2861
2862
2863 /*[clinic input]
2864 os.lstat
2865
2866 path : path_t
2867
2868 *
2869
2870 dir_fd : dir_fd(requires='fstatat') = None
2871
2872 Perform a stat system call on the given path, without following symbolic links.
2873
2874 Like stat(), but do not follow symbolic links.
2875 Equivalent to stat(path, follow_symlinks=False).
2876 [clinic start generated code]*/
2877
2878 static PyObject *
2879 120910 os_lstat_impl(PyObject *module, path_t *path, int dir_fd)
2880 /*[clinic end generated code: output=ef82a5d35ce8ab37 input=0b7474765927b925]*/
2881 {
2882 120910 int follow_symlinks = 0;
2883 120910 return posix_do_stat(module, "lstat", path, dir_fd, follow_symlinks);
2884 }
2885
2886
2887 /*[clinic input]
2888 os.access -> bool
2889
2890 path: path_t
2891 Path to be tested; can be string, bytes, or a path-like object.
2892
2893 mode: int
2894 Operating-system mode bitfield. Can be F_OK to test existence,
2895 or the inclusive-OR of R_OK, W_OK, and X_OK.
2896
2897 *
2898
2899 dir_fd : dir_fd(requires='faccessat') = None
2900 If not None, it should be a file descriptor open to a directory,
2901 and path should be relative; path will then be relative to that
2902 directory.
2903
2904 effective_ids: bool = False
2905 If True, access will use the effective uid/gid instead of
2906 the real uid/gid.
2907
2908 follow_symlinks: bool = True
2909 If False, and the last element of the path is a symbolic link,
2910 access will examine the symbolic link itself instead of the file
2911 the link points to.
2912
2913 Use the real uid/gid to test for access to a path.
2914
2915 {parameters}
2916 dir_fd, effective_ids, and follow_symlinks may not be implemented
2917 on your platform. If they are unavailable, using them will raise a
2918 NotImplementedError.
2919
2920 Note that most operations will use the effective uid/gid, therefore this
2921 routine can be used in a suid/sgid environment to test if the invoking user
2922 has the specified access to the path.
2923
2924 [clinic start generated code]*/
2925
2926 static int
2927 461 os_access_impl(PyObject *module, path_t *path, int mode, int dir_fd,
2928 int effective_ids, int follow_symlinks)
2929 /*[clinic end generated code: output=cf84158bc90b1a77 input=3ffe4e650ee3bf20]*/
2930 {
2931 int return_value;
2932
2933 #ifdef MS_WINDOWS
2934 DWORD attr;
2935 #else
2936 int result;
2937 #endif
2938
2939 #ifdef HAVE_FACCESSAT
2940 461 int faccessat_unavailable = 0;
2941 #endif
2942
2943 #ifndef HAVE_FACCESSAT
2944 if (follow_symlinks_specified("access", follow_symlinks))
2945 return -1;
2946
2947 if (effective_ids) {
2948 argument_unavailable_error("access", "effective_ids");
2949 return -1;
2950 }
2951 #endif
2952
2953 #ifdef MS_WINDOWS
2954 Py_BEGIN_ALLOW_THREADS
2955 attr = GetFileAttributesW(path->wide);
2956 Py_END_ALLOW_THREADS
2957
2958 /*
2959 * Access is possible if
2960 * * we didn't get a -1, and
2961 * * write access wasn't requested,
2962 * * or the file isn't read-only,
2963 * * or it's a directory.
2964 * (Directories cannot be read-only on Windows.)
2965 */
2966 return_value = (attr != INVALID_FILE_ATTRIBUTES) &&
2967 (!(mode & 2) ||
2968 !(attr & FILE_ATTRIBUTE_READONLY) ||
2969 (attr & FILE_ATTRIBUTE_DIRECTORY));
2970 #else
2971
2972 461 Py_BEGIN_ALLOW_THREADS
2973 #ifdef HAVE_FACCESSAT
2974
2/4
✓ Branch 0 taken 461 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 461 times.
✗ Branch 3 not taken.
461 if ((dir_fd != DEFAULT_DIR_FD) ||
2975
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 461 times.
461 effective_ids ||
2976 !follow_symlinks) {
2977
2978 if (HAVE_FACCESSAT_RUNTIME) {
2979 int flags = 0;
2980 if (!follow_symlinks)
2981 flags |= AT_SYMLINK_NOFOLLOW;
2982 if (effective_ids)
2983 flags |= AT_EACCESS;
2984 result = faccessat(dir_fd, path->narrow, mode, flags);
2985 } else {
2986 faccessat_unavailable = 1;
2987 }
2988 }
2989 else
2990 #endif
2991 461 result = access(path->narrow, mode);
2992 461 Py_END_ALLOW_THREADS
2993
2994 #ifdef HAVE_FACCESSAT
2995
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 461 times.
461 if (faccessat_unavailable) {
2996 if (dir_fd != DEFAULT_DIR_FD) {
2997 argument_unavailable_error("access", "dir_fd");
2998 return -1;
2999 }
3000 if (follow_symlinks_specified("access", follow_symlinks))
3001 return -1;
3002
3003 if (effective_ids) {
3004 argument_unavailable_error("access", "effective_ids");
3005 return -1;
3006 }
3007 /* should be unreachable */
3008 return -1;
3009 }
3010 #endif
3011 461 return_value = !result;
3012 #endif
3013
3014 461 return return_value;
3015 }
3016
3017 #ifndef F_OK
3018 #define F_OK 0
3019 #endif
3020 #ifndef R_OK
3021 #define R_OK 4
3022 #endif
3023 #ifndef W_OK
3024 #define W_OK 2
3025 #endif
3026 #ifndef X_OK
3027 #define X_OK 1
3028 #endif
3029
3030
3031 #ifdef HAVE_TTYNAME
3032 /*[clinic input]
3033 os.ttyname
3034
3035 fd: int
3036 Integer file descriptor handle.
3037
3038 /
3039
3040 Return the name of the terminal device connected to 'fd'.
3041 [clinic start generated code]*/
3042
3043 static PyObject *
3044 os_ttyname_impl(PyObject *module, int fd)
3045 /*[clinic end generated code: output=c424d2e9d1cd636a input=9ff5a58b08115c55]*/
3046 {
3047
3048 long size = sysconf(_SC_TTY_NAME_MAX);
3049 if (size == -1) {
3050 return posix_error();
3051 }
3052 char *buffer = (char *)PyMem_RawMalloc(size);
3053 if (buffer == NULL) {
3054 return PyErr_NoMemory();
3055 }
3056 int ret = ttyname_r(fd, buffer, size);
3057 if (ret != 0) {
3058 PyMem_RawFree(buffer);
3059 errno = ret;
3060 return posix_error();
3061 }
3062 PyObject *res = PyUnicode_DecodeFSDefault(buffer);
3063 PyMem_RawFree(buffer);
3064 return res;
3065 }
3066 #endif
3067
3068 #ifdef HAVE_CTERMID
3069 /*[clinic input]
3070 os.ctermid
3071
3072 Return the name of the controlling terminal for this process.
3073 [clinic start generated code]*/
3074
3075 static PyObject *
3076 os_ctermid_impl(PyObject *module)
3077 /*[clinic end generated code: output=02f017e6c9e620db input=3b87fdd52556382d]*/
3078 {
3079 char *ret;
3080 char buffer[L_ctermid];
3081
3082 #ifdef USE_CTERMID_R
3083 ret = ctermid_r(buffer);
3084 #else
3085 ret = ctermid(buffer);
3086 #endif
3087 if (ret == NULL)
3088 return posix_error();
3089 return PyUnicode_DecodeFSDefault(buffer);
3090 }
3091 #endif /* HAVE_CTERMID */
3092
3093
3094 /*[clinic input]
3095 os.chdir
3096
3097 path: path_t(allow_fd='PATH_HAVE_FCHDIR')
3098
3099 Change the current working directory to the specified path.
3100
3101 path may always be specified as a string.
3102 On some platforms, path may also be specified as an open file descriptor.
3103 If this functionality is unavailable, using it raises an exception.
3104 [clinic start generated code]*/
3105
3106 static PyObject *
3107 os_chdir_impl(PyObject *module, path_t *path)
3108 /*[clinic end generated code: output=3be6400eee26eaae input=1a4a15b4d12cb15d]*/
3109 {
3110 int result;
3111
3112 if (PySys_Audit("os.chdir", "(O)", path->object) < 0) {
3113 return NULL;
3114 }
3115
3116 Py_BEGIN_ALLOW_THREADS
3117 #ifdef MS_WINDOWS
3118 /* on unix, success = 0, on windows, success = !0 */
3119 result = !win32_wchdir(path->wide);
3120 #else
3121 #ifdef HAVE_FCHDIR
3122 if (path->fd != -1)
3123 result = fchdir(path->fd);
3124 else
3125 #endif
3126 result = chdir(path->narrow);
3127 #endif
3128 Py_END_ALLOW_THREADS
3129
3130 if (result) {
3131 return path_error(path);
3132 }
3133
3134 Py_RETURN_NONE;
3135 }
3136
3137
3138 #ifdef HAVE_FCHDIR
3139 /*[clinic input]
3140 os.fchdir
3141
3142 fd: fildes
3143
3144 Change to the directory of the given file descriptor.
3145
3146 fd must be opened on a directory, not a file.
3147 Equivalent to os.chdir(fd).
3148
3149 [clinic start generated code]*/
3150
3151 static PyObject *
3152 os_fchdir_impl(PyObject *module, int fd)
3153 /*[clinic end generated code: output=42e064ec4dc00ab0 input=18e816479a2fa985]*/
3154 {
3155 if (PySys_Audit("os.chdir", "(i)", fd) < 0) {
3156 return NULL;
3157 }
3158 return posix_fildes_fd(fd, fchdir);
3159 }
3160 #endif /* HAVE_FCHDIR */
3161
3162
3163 /*[clinic input]
3164 os.chmod
3165
3166 path: path_t(allow_fd='PATH_HAVE_FCHMOD')
3167 Path to be modified. May always be specified as a str, bytes, or a path-like object.
3168 On some platforms, path may also be specified as an open file descriptor.
3169 If this functionality is unavailable, using it raises an exception.
3170
3171 mode: int
3172 Operating-system mode bitfield.
3173
3174 *
3175
3176 dir_fd : dir_fd(requires='fchmodat') = None
3177 If not None, it should be a file descriptor open to a directory,
3178 and path should be relative; path will then be relative to that
3179 directory.
3180
3181 follow_symlinks: bool = True
3182 If False, and the last element of the path is a symbolic link,
3183 chmod will modify the symbolic link itself instead of the file
3184 the link points to.
3185
3186 Change the access permissions of a file.
3187
3188 It is an error to use dir_fd or follow_symlinks when specifying path as
3189 an open file descriptor.
3190 dir_fd and follow_symlinks may not be implemented on your platform.
3191 If they are unavailable, using them will raise a NotImplementedError.
3192
3193 [clinic start generated code]*/
3194
3195 static PyObject *
3196 1201 os_chmod_impl(PyObject *module, path_t *path, int mode, int dir_fd,
3197 int follow_symlinks)
3198 /*[clinic end generated code: output=5cf6a94915cc7bff input=989081551c00293b]*/
3199 {
3200 int result;
3201
3202 #ifdef MS_WINDOWS
3203 DWORD attr;
3204 #endif
3205
3206 #ifdef HAVE_FCHMODAT
3207 1201 int fchmodat_nofollow_unsupported = 0;
3208 1201 int fchmodat_unsupported = 0;
3209 #endif
3210
3211 #if !(defined(HAVE_FCHMODAT) || defined(HAVE_LCHMOD))
3212 if (follow_symlinks_specified("chmod", follow_symlinks))
3213 return NULL;
3214 #endif
3215
3216
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1201 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1201 times.
1201 if (PySys_Audit("os.chmod", "Oii", path->object, mode,
3217 dir_fd == DEFAULT_DIR_FD ? -1 : dir_fd) < 0) {
3218 return NULL;
3219 }
3220
3221 #ifdef MS_WINDOWS
3222 Py_BEGIN_ALLOW_THREADS
3223 attr = GetFileAttributesW(path->wide);
3224 if (attr == INVALID_FILE_ATTRIBUTES)
3225 result = 0;
3226 else {
3227 if (mode & _S_IWRITE)
3228 attr &= ~FILE_ATTRIBUTE_READONLY;
3229 else
3230 attr |= FILE_ATTRIBUTE_READONLY;
3231 result = SetFileAttributesW(path->wide, attr);
3232 }
3233 Py_END_ALLOW_THREADS
3234
3235 if (!result) {
3236 return path_error(path);
3237 }
3238 #else /* MS_WINDOWS */
3239 1201 Py_BEGIN_ALLOW_THREADS
3240 #ifdef HAVE_FCHMOD
3241
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1201 times.
1201 if (path->fd != -1)
3242 result = fchmod(path->fd, mode);
3243 else
3244 #endif /* HAVE_CHMOD */
3245 #ifdef HAVE_LCHMOD
3246 if ((!follow_symlinks) && (dir_fd == DEFAULT_DIR_FD))
3247 result = lchmod(path->narrow, mode);
3248 else
3249 #endif /* HAVE_LCHMOD */
3250 #ifdef HAVE_FCHMODAT
3251
2/4
✓ Branch 0 taken 1201 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1201 times.
1201 if ((dir_fd != DEFAULT_DIR_FD) || !follow_symlinks) {
3252 if (HAVE_FCHMODAT_RUNTIME) {
3253 /*
3254 * fchmodat() doesn't currently support AT_SYMLINK_NOFOLLOW!
3255 * The documentation specifically shows how to use it,
3256 * and then says it isn't implemented yet.
3257 * (true on linux with glibc 2.15, and openindiana 3.x)
3258 *
3259 * Once it is supported, os.chmod will automatically
3260 * support dir_fd and follow_symlinks=False. (Hopefully.)
3261 * Until then, we need to be careful what exception we raise.
3262 */
3263 result = fchmodat(dir_fd, path->narrow, mode,
3264 follow_symlinks ? 0 : AT_SYMLINK_NOFOLLOW);
3265 /*
3266 * But wait! We can't throw the exception without allowing threads,
3267 * and we can't do that in this nested scope. (Macro trickery, sigh.)
3268 */
3269 fchmodat_nofollow_unsupported =
3270 result &&
3271 ((errno == ENOTSUP) || (errno == EOPNOTSUPP)) &&
3272 !follow_symlinks;
3273 } else {
3274 fchmodat_unsupported = 1;
3275 fchmodat_nofollow_unsupported = 1;
3276
3277 result = -1;
3278 }
3279 }
3280 else
3281 #endif /* HAVE_FHCMODAT */
3282 {
3283 #ifdef HAVE_CHMOD
3284 1201 result = chmod(path->narrow, mode);
3285 #elif defined(__wasi__)
3286 // WASI SDK 15.0 does not support chmod.
3287 // Ignore missing syscall for now.
3288 result = 0;
3289 #else
3290 result = -1;
3291 errno = ENOSYS;
3292 #endif
3293 }
3294 1201 Py_END_ALLOW_THREADS
3295
3296
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1201 times.
1201 if (result) {
3297 #ifdef HAVE_FCHMODAT
3298 if (fchmodat_unsupported) {
3299 if (dir_fd != DEFAULT_DIR_FD) {
3300 argument_unavailable_error("chmod", "dir_fd");
3301 return NULL;
3302 }
3303 }
3304
3305 if (fchmodat_nofollow_unsupported) {
3306 if (dir_fd != DEFAULT_DIR_FD)
3307 dir_fd_and_follow_symlinks_invalid("chmod",
3308 dir_fd, follow_symlinks);
3309 else
3310 follow_symlinks_specified("chmod", follow_symlinks);
3311 return NULL;
3312 }
3313 else
3314 #endif /* HAVE_FCHMODAT */
3315 return path_error(path);
3316 }
3317 #endif /* MS_WINDOWS */
3318
3319 1201 Py_RETURN_NONE;
3320 }
3321
3322
3323 #ifdef HAVE_FCHMOD
3324 /*[clinic input]
3325 os.fchmod
3326
3327 fd: int
3328 mode: int
3329
3330 Change the access permissions of the file given by file descriptor fd.
3331
3332 Equivalent to os.chmod(fd, mode).
3333 [clinic start generated code]*/
3334
3335 static PyObject *
3336 os_fchmod_impl(PyObject *module, int fd, int mode)
3337 /*[clinic end generated code: output=afd9bc05b4e426b3 input=8ab11975ca01ee5b]*/
3338 {
3339 int res;
3340 int async_err = 0;
3341
3342 if (PySys_Audit("os.chmod", "iii", fd, mode, -1) < 0) {
3343 return NULL;
3344 }
3345
3346 do {
3347 Py_BEGIN_ALLOW_THREADS
3348 res = fchmod(fd, mode);
3349 Py_END_ALLOW_THREADS
3350 } while (res != 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
3351 if (res != 0)
3352 return (!async_err) ? posix_error() : NULL;
3353
3354 Py_RETURN_NONE;
3355 }
3356 #endif /* HAVE_FCHMOD */
3357
3358
3359 #ifdef HAVE_LCHMOD
3360 /*[clinic input]
3361 os.lchmod
3362
3363 path: path_t
3364 mode: int
3365
3366 Change the access permissions of a file, without following symbolic links.
3367
3368 If path is a symlink, this affects the link itself rather than the target.
3369 Equivalent to chmod(path, mode, follow_symlinks=False)."
3370 [clinic start generated code]*/
3371
3372 static PyObject *
3373 os_lchmod_impl(PyObject *module, path_t *path, int mode)
3374 /*[clinic end generated code: output=082344022b51a1d5 input=90c5663c7465d24f]*/
3375 {
3376 int res;
3377 if (PySys_Audit("os.chmod", "Oii", path->object, mode, -1) < 0) {
3378 return NULL;
3379 }
3380 Py_BEGIN_ALLOW_THREADS
3381 res = lchmod(path->narrow, mode);
3382 Py_END_ALLOW_THREADS
3383 if (res < 0) {
3384 path_error(path);
3385 return NULL;
3386 }
3387 Py_RETURN_NONE;
3388 }
3389 #endif /* HAVE_LCHMOD */
3390
3391
3392 #ifdef HAVE_CHFLAGS
3393 /*[clinic input]
3394 os.chflags
3395
3396 path: path_t
3397 flags: unsigned_long(bitwise=True)
3398 follow_symlinks: bool=True
3399
3400 Set file flags.
3401
3402 If follow_symlinks is False, and the last element of the path is a symbolic
3403 link, chflags will change flags on the symbolic link itself instead of the
3404 file the link points to.
3405 follow_symlinks may not be implemented on your platform. If it is
3406 unavailable, using it will raise a NotImplementedError.
3407
3408 [clinic start generated code]*/
3409
3410 static PyObject *
3411 os_chflags_impl(PyObject *module, path_t *path, unsigned long flags,
3412 int follow_symlinks)
3413 /*[clinic end generated code: output=85571c6737661ce9 input=0327e29feb876236]*/
3414 {
3415 int result;
3416
3417 #ifndef HAVE_LCHFLAGS
3418 if (follow_symlinks_specified("chflags", follow_symlinks))
3419 return NULL;
3420 #endif
3421
3422 if (PySys_Audit("os.chflags", "Ok", path->object, flags) < 0) {
3423 return NULL;
3424 }
3425
3426 Py_BEGIN_ALLOW_THREADS
3427 #ifdef HAVE_LCHFLAGS
3428 if (!follow_symlinks)
3429 result = lchflags(path->narrow, flags);
3430 else
3431 #endif
3432 result = chflags(path->narrow, flags);
3433 Py_END_ALLOW_THREADS
3434
3435 if (result)
3436 return path_error(path);
3437
3438 Py_RETURN_NONE;
3439 }
3440 #endif /* HAVE_CHFLAGS */
3441
3442
3443 #ifdef HAVE_LCHFLAGS
3444 /*[clinic input]
3445 os.lchflags
3446
3447 path: path_t
3448 flags: unsigned_long(bitwise=True)
3449
3450 Set file flags.
3451
3452 This function will not follow symbolic links.
3453 Equivalent to chflags(path, flags, follow_symlinks=False).
3454 [clinic start generated code]*/
3455
3456 static PyObject *
3457 os_lchflags_impl(PyObject *module, path_t *path, unsigned long flags)
3458 /*[clinic end generated code: output=30ae958695c07316 input=f9f82ea8b585ca9d]*/
3459 {
3460 int res;
3461 if (PySys_Audit("os.chflags", "Ok", path->object, flags) < 0) {
3462 return NULL;
3463 }
3464 Py_BEGIN_ALLOW_THREADS
3465 res = lchflags(path->narrow, flags);
3466 Py_END_ALLOW_THREADS
3467 if (res < 0) {
3468 return path_error(path);
3469 }
3470 Py_RETURN_NONE;
3471 }
3472 #endif /* HAVE_LCHFLAGS */
3473
3474
3475 #ifdef HAVE_CHROOT
3476 /*[clinic input]
3477 os.chroot
3478 path: path_t
3479
3480 Change root directory to path.
3481
3482 [clinic start generated code]*/
3483
3484 static PyObject *
3485 os_chroot_impl(PyObject *module, path_t *path)
3486 /*[clinic end generated code: output=de80befc763a4475 input=14822965652c3dc3]*/
3487 {
3488 int res;
3489 Py_BEGIN_ALLOW_THREADS
3490 res = chroot(path->narrow);
3491 Py_END_ALLOW_THREADS
3492 if (res < 0)
3493 return path_error(path);
3494 Py_RETURN_NONE;
3495 }
3496 #endif /* HAVE_CHROOT */
3497
3498
3499 #ifdef HAVE_FSYNC
3500 /*[clinic input]
3501 os.fsync
3502
3503 fd: fildes
3504
3505 Force write of fd to disk.
3506 [clinic start generated code]*/
3507
3508 static PyObject *
3509 81 os_fsync_impl(PyObject *module, int fd)
3510 /*[clinic end generated code: output=4a10d773f52b3584 input=21c3645c056967f2]*/
3511 {
3512 81 return posix_fildes_fd(fd, fsync);
3513 }
3514 #endif /* HAVE_FSYNC */
3515
3516
3517 #ifdef HAVE_SYNC
3518 /*[clinic input]
3519 os.sync
3520
3521 Force write of everything to disk.
3522 [clinic start generated code]*/
3523
3524 static PyObject *
3525 os_sync_impl(PyObject *module)
3526 /*[clinic end generated code: output=2796b1f0818cd71c input=84749fe5e9b404ff]*/
3527 {
3528 Py_BEGIN_ALLOW_THREADS
3529 sync();
3530 Py_END_ALLOW_THREADS
3531 Py_RETURN_NONE;
3532 }
3533 #endif /* HAVE_SYNC */
3534
3535
3536 #ifdef HAVE_FDATASYNC
3537 #ifdef __hpux
3538 extern int fdatasync(int); /* On HP-UX, in libc but not in unistd.h */
3539 #endif
3540
3541 /*[clinic input]
3542 os.fdatasync
3543
3544 fd: fildes
3545
3546 Force write of fd to disk without forcing update of metadata.
3547 [clinic start generated code]*/
3548
3549 static PyObject *
3550 os_fdatasync_impl(PyObject *module, int fd)
3551 /*[clinic end generated code: output=b4b9698b5d7e26dd input=bc74791ee54dd291]*/
3552 {
3553 return posix_fildes_fd(fd, fdatasync);
3554 }
3555 #endif /* HAVE_FDATASYNC */
3556
3557
3558 #ifdef HAVE_CHOWN
3559 /*[clinic input]
3560 os.chown
3561
3562 path : path_t(allow_fd='PATH_HAVE_FCHOWN')
3563 Path to be examined; can be string, bytes, a path-like object, or open-file-descriptor int.
3564
3565 uid: uid_t
3566
3567 gid: gid_t
3568
3569 *
3570
3571 dir_fd : dir_fd(requires='fchownat') = None
3572 If not None, it should be a file descriptor open to a directory,
3573 and path should be relative; path will then be relative to that
3574 directory.
3575
3576 follow_symlinks: bool = True
3577 If False, and the last element of the path is a symbolic link,
3578 stat will examine the symbolic link itself instead of the file
3579 the link points to.
3580
3581 Change the owner and group id of path to the numeric uid and gid.\
3582
3583 path may always be specified as a string.
3584 On some platforms, path may also be specified as an open file descriptor.
3585 If this functionality is unavailable, using it raises an exception.
3586 If dir_fd is not None, it should be a file descriptor open to a directory,
3587 and path should be relative; path will then be relative to that directory.
3588 If follow_symlinks is False, and the last element of the path is a symbolic
3589 link, chown will modify the symbolic link itself instead of the file the
3590 link points to.
3591 It is an error to use dir_fd or follow_symlinks when specifying path as
3592 an open file descriptor.
3593 dir_fd and follow_symlinks may not be implemented on your platform.
3594 If they are unavailable, using them will raise a NotImplementedError.
3595
3596 [clinic start generated code]*/
3597
3598 static PyObject *
3599 os_chown_impl(PyObject *module, path_t *path, uid_t uid, gid_t gid,
3600 int dir_fd, int follow_symlinks)
3601 /*[clinic end generated code: output=4beadab0db5f70cd input=b08c5ec67996a97d]*/
3602 {
3603 int result;
3604
3605 #if defined(HAVE_FCHOWNAT)
3606 int fchownat_unsupported = 0;
3607 #endif
3608
3609 #if !(defined(HAVE_LCHOWN) || defined(HAVE_FCHOWNAT))
3610 if (follow_symlinks_specified("chown", follow_symlinks))
3611 return NULL;
3612 #endif
3613 if (dir_fd_and_fd_invalid("chown", dir_fd, path->fd) ||
3614 fd_and_follow_symlinks_invalid("chown", path->fd, follow_symlinks))
3615 return NULL;
3616
3617 if (PySys_Audit("os.chown", "OIIi", path->object, uid, gid,
3618 dir_fd == DEFAULT_DIR_FD ? -1 : dir_fd) < 0) {
3619 return NULL;
3620 }
3621
3622 Py_BEGIN_ALLOW_THREADS
3623 #ifdef HAVE_FCHOWN
3624 if (path->fd != -1)
3625 result = fchown(path->fd, uid, gid);
3626 else
3627 #endif
3628 #ifdef HAVE_LCHOWN
3629 if ((!follow_symlinks) && (dir_fd == DEFAULT_DIR_FD))
3630 result = lchown(path->narrow, uid, gid);
3631 else
3632 #endif
3633 #ifdef HAVE_FCHOWNAT
3634 if ((dir_fd != DEFAULT_DIR_FD) || (!follow_symlinks)) {
3635 if (HAVE_FCHOWNAT_RUNTIME) {
3636 result = fchownat(dir_fd, path->narrow, uid, gid,
3637 follow_symlinks ? 0 : AT_SYMLINK_NOFOLLOW);
3638 } else {
3639 fchownat_unsupported = 1;
3640 }
3641 } else
3642 #endif
3643 result = chown(path->narrow, uid, gid);
3644 Py_END_ALLOW_THREADS
3645
3646 #ifdef HAVE_FCHOWNAT
3647 if (fchownat_unsupported) {
3648 /* This would be incorrect if the current platform
3649 * doesn't support lchown.
3650 */
3651 argument_unavailable_error(NULL, "dir_fd");
3652 return NULL;
3653 }
3654 #endif
3655
3656 if (result)
3657 return path_error(path);
3658
3659 Py_RETURN_NONE;
3660 }
3661 #endif /* HAVE_CHOWN */
3662
3663
3664 #ifdef HAVE_FCHOWN
3665 /*[clinic input]
3666 os.fchown
3667
3668 fd: int
3669 uid: uid_t
3670 gid: gid_t
3671
3672 Change the owner and group id of the file specified by file descriptor.
3673
3674 Equivalent to os.chown(fd, uid, gid).
3675
3676 [clinic start generated code]*/
3677
3678 static PyObject *
3679 os_fchown_impl(PyObject *module, int fd, uid_t uid, gid_t gid)
3680 /*[clinic end generated code: output=97d21cbd5a4350a6 input=3af544ba1b13a0d7]*/
3681 {
3682 int res;
3683 int async_err = 0;
3684
3685 if (PySys_Audit("os.chown", "iIIi", fd, uid, gid, -1) < 0) {
3686 return NULL;
3687 }
3688
3689 do {
3690 Py_BEGIN_ALLOW_THREADS
3691 res = fchown(fd, uid, gid);
3692 Py_END_ALLOW_THREADS
3693 } while (res != 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
3694 if (res != 0)
3695 return (!async_err) ? posix_error() : NULL;
3696
3697 Py_RETURN_NONE;
3698 }
3699 #endif /* HAVE_FCHOWN */
3700
3701
3702 #ifdef HAVE_LCHOWN
3703 /*[clinic input]
3704 os.lchown
3705
3706 path : path_t
3707 uid: uid_t
3708 gid: gid_t
3709
3710 Change the owner and group id of path to the numeric uid and gid.
3711
3712 This function will not follow symbolic links.
3713 Equivalent to os.chown(path, uid, gid, follow_symlinks=False).
3714 [clinic start generated code]*/
3715
3716 static PyObject *
3717 os_lchown_impl(PyObject *module, path_t *path, uid_t uid, gid_t gid)
3718 /*[clinic end generated code: output=25eaf6af412fdf2f input=b1c6014d563a7161]*/
3719 {
3720 int res;
3721 if (PySys_Audit("os.chown", "OIIi", path->object, uid, gid, -1) < 0) {
3722 return NULL;
3723 }
3724 Py_BEGIN_ALLOW_THREADS
3725 res = lchown(path->narrow, uid, gid);
3726 Py_END_ALLOW_THREADS
3727 if (res < 0) {
3728 return path_error(path);
3729 }
3730 Py_RETURN_NONE;
3731 }
3732 #endif /* HAVE_LCHOWN */
3733
3734
3735 static PyObject *
3736 9828 posix_getcwd(int use_bytes)
3737 {
3738 #ifdef MS_WINDOWS
3739 wchar_t wbuf[MAXPATHLEN];
3740 wchar_t *wbuf2 = wbuf;
3741 DWORD len;
3742
3743 Py_BEGIN_ALLOW_THREADS
3744 len = GetCurrentDirectoryW(Py_ARRAY_LENGTH(wbuf), wbuf);
3745 /* If the buffer is large enough, len does not include the
3746 terminating \0. If the buffer is too small, len includes
3747 the space needed for the terminator. */
3748 if (len >= Py_ARRAY_LENGTH(wbuf)) {
3749 if (len <= PY_SSIZE_T_MAX / sizeof(wchar_t)) {
3750 wbuf2 = PyMem_RawMalloc(len * sizeof(wchar_t));
3751 }
3752 else {
3753 wbuf2 = NULL;
3754 }
3755 if (wbuf2) {
3756 len = GetCurrentDirectoryW(len, wbuf2);
3757 }
3758 }
3759 Py_END_ALLOW_THREADS
3760
3761 if (!wbuf2) {
3762 PyErr_NoMemory();
3763 return NULL;
3764 }
3765 if (!len) {
3766 if (wbuf2 != wbuf)
3767 PyMem_RawFree(wbuf2);
3768 return PyErr_SetFromWindowsErr(0);
3769 }
3770
3771 PyObject *resobj = PyUnicode_FromWideChar(wbuf2, len);
3772 if (wbuf2 != wbuf) {
3773 PyMem_RawFree(wbuf2);
3774 }
3775
3776 if (use_bytes) {
3777 if (resobj == NULL) {
3778 return NULL;
3779 }
3780 Py_SETREF(resobj, PyUnicode_EncodeFSDefault(resobj));
3781 }
3782
3783 return resobj;
3784 #else
3785 9828 const size_t chunk = 1024;
3786
3787 9828 char *buf = NULL;
3788 9828 char *cwd = NULL;
3789 9828 size_t buflen = 0;
3790
3791 9828 Py_BEGIN_ALLOW_THREADS
3792 do {
3793 char *newbuf;
3794
1/2
✓ Branch 0 taken 9828 times.
✗ Branch 1 not taken.
9828 if (buflen <= PY_SSIZE_T_MAX - chunk) {
3795 9828 buflen += chunk;
3796 9828 newbuf = PyMem_RawRealloc(buf, buflen);
3797 }
3798 else {
3799 newbuf = NULL;
3800 }
3801
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9828 times.
9828 if (newbuf == NULL) {
3802 PyMem_RawFree(buf);
3803 buf = NULL;
3804 break;
3805 }
3806 9828 buf = newbuf;
3807
3808 9828 cwd = getcwd(buf, buflen);
3809
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 9828 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
9828 } while (cwd == NULL && errno == ERANGE);
3810 9828 Py_END_ALLOW_THREADS
3811
3812
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9828 times.
9828 if (buf == NULL) {
3813 return PyErr_NoMemory();
3814 }
3815
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9828 times.
9828 if (cwd == NULL) {
3816 PyMem_RawFree(buf);
3817 return posix_error();
3818 }
3819
3820 PyObject *obj;
3821
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9828 times.
9828 if (use_bytes) {
3822 obj = PyBytes_FromStringAndSize(buf, strlen(buf));
3823 }
3824 else {
3825 9828 obj = PyUnicode_DecodeFSDefault(buf);
3826 }
3827 9828 PyMem_RawFree(buf);
3828
3829 9828 return obj;
3830 #endif /* !MS_WINDOWS */
3831 }
3832
3833
3834 /*[clinic input]
3835 os.getcwd
3836
3837 Return a unicode string representing the current working directory.
3838 [clinic start generated code]*/
3839
3840 static PyObject *
3841 9828 os_getcwd_impl(PyObject *module)
3842 /*[clinic end generated code: output=21badfae2ea99ddc input=f069211bb70e3d39]*/
3843 {
3844 9828 return posix_getcwd(0);
3845 }
3846
3847
3848 /*[clinic input]
3849 os.getcwdb
3850
3851 Return a bytes string representing the current working directory.
3852 [clinic start generated code]*/
3853
3854 static PyObject *
3855 os_getcwdb_impl(PyObject *module)
3856 /*[clinic end generated code: output=3dd47909480e4824 input=f6f6a378dad3d9cb]*/
3857 {
3858 return posix_getcwd(1);
3859 }
3860
3861
3862 #if ((!defined(HAVE_LINK)) && defined(MS_WINDOWS))
3863 #define HAVE_LINK 1
3864 #endif
3865
3866 #ifdef HAVE_LINK
3867 /*[clinic input]
3868
3869 os.link
3870
3871 src : path_t
3872 dst : path_t
3873 *
3874 src_dir_fd : dir_fd = None
3875 dst_dir_fd : dir_fd = None
3876 follow_symlinks: bool = True
3877
3878 Create a hard link to a file.
3879
3880 If either src_dir_fd or dst_dir_fd is not None, it should be a file
3881 descriptor open to a directory, and the respective path string (src or dst)
3882 should be relative; the path will then be relative to that directory.
3883 If follow_symlinks is False, and the last element of src is a symbolic
3884 link, link will create a link to the symbolic link itself instead of the
3885 file the link points to.
3886 src_dir_fd, dst_dir_fd, and follow_symlinks may not be implemented on your
3887 platform. If they are unavailable, using them will raise a
3888 NotImplementedError.
3889 [clinic start generated code]*/
3890
3891 static PyObject *
3892 os_link_impl(PyObject *module, path_t *src, path_t *dst, int src_dir_fd,
3893 int dst_dir_fd, int follow_symlinks)
3894 /*[clinic end generated code: output=7f00f6007fd5269a input=b0095ebbcbaa7e04]*/
3895 {
3896 #ifdef MS_WINDOWS
3897 BOOL result = FALSE;
3898 #else
3899 int result;
3900 #endif
3901 #if defined(HAVE_LINKAT)
3902 int linkat_unavailable = 0;
3903 #endif
3904
3905 #ifndef HAVE_LINKAT
3906 if ((src_dir_fd != DEFAULT_DIR_FD) || (dst_dir_fd != DEFAULT_DIR_FD)) {
3907 argument_unavailable_error("link", "src_dir_fd and dst_dir_fd");
3908 return NULL;
3909 }
3910 #endif
3911
3912 #ifndef MS_WINDOWS
3913 if ((src->narrow && dst->wide) || (src->wide && dst->narrow)) {
3914 PyErr_SetString(PyExc_NotImplementedError,
3915 "link: src and dst must be the same type");
3916 return NULL;
3917 }
3918 #endif
3919
3920 if (PySys_Audit("os.link", "OOii", src->object, dst->object,
3921 src_dir_fd == DEFAULT_DIR_FD ? -1 : src_dir_fd,
3922 dst_dir_fd == DEFAULT_DIR_FD ? -1 : dst_dir_fd) < 0) {
3923 return NULL;
3924 }
3925
3926 #ifdef MS_WINDOWS
3927 Py_BEGIN_ALLOW_THREADS
3928 result = CreateHardLinkW(dst->wide, src->wide, NULL);
3929 Py_END_ALLOW_THREADS
3930
3931 if (!result)
3932 return path_error2(src, dst);
3933 #else
3934 Py_BEGIN_ALLOW_THREADS
3935 #ifdef HAVE_LINKAT
3936 if ((src_dir_fd != DEFAULT_DIR_FD) ||
3937 (dst_dir_fd != DEFAULT_DIR_FD) ||
3938 (!follow_symlinks)) {
3939
3940 if (HAVE_LINKAT_RUNTIME) {
3941
3942 result = linkat(src_dir_fd, src->narrow,
3943 dst_dir_fd, dst->narrow,
3944 follow_symlinks ? AT_SYMLINK_FOLLOW : 0);
3945
3946 }
3947 #ifdef __APPLE__
3948 else {
3949 if (src_dir_fd == DEFAULT_DIR_FD && dst_dir_fd == DEFAULT_DIR_FD) {
3950 /* See issue 41355: This matches the behaviour of !HAVE_LINKAT */
3951 result = link(src->narrow, dst->narrow);
3952 } else {
3953 linkat_unavailable = 1;
3954 }
3955 }
3956 #endif
3957 }
3958 else
3959 #endif /* HAVE_LINKAT */
3960 result = link(src->narrow, dst->narrow);
3961 Py_END_ALLOW_THREADS
3962
3963 #ifdef HAVE_LINKAT
3964 if (linkat_unavailable) {
3965 /* Either or both dir_fd arguments were specified */
3966 if (src_dir_fd != DEFAULT_DIR_FD) {
3967 argument_unavailable_error("link", "src_dir_fd");
3968 } else {
3969 argument_unavailable_error("link", "dst_dir_fd");
3970 }
3971 return NULL;
3972 }
3973 #endif
3974
3975 if (result)
3976 return path_error2(src, dst);
3977 #endif /* MS_WINDOWS */
3978
3979 Py_RETURN_NONE;
3980 }
3981 #endif
3982
3983
3984 #if defined(MS_WINDOWS) && !defined(HAVE_OPENDIR)
3985 static PyObject *
3986 _listdir_windows_no_opendir(path_t *path, PyObject *list)
3987 {
3988 PyObject *v;
3989 HANDLE hFindFile = INVALID_HANDLE_VALUE;
3990 BOOL result;
3991 wchar_t namebuf[MAX_PATH+4]; /* Overallocate for "\*.*" */
3992 /* only claim to have space for MAX_PATH */
3993 Py_ssize_t len = Py_ARRAY_LENGTH(namebuf)-4;
3994 wchar_t *wnamebuf = NULL;
3995
3996 WIN32_FIND_DATAW wFileData;
3997 const wchar_t *po_wchars;
3998
3999 if (!path->wide) { /* Default arg: "." */
4000 po_wchars = L".";
4001 len = 1;
4002 } else {
4003 po_wchars = path->wide;
4004 len = wcslen(path->wide);
4005 }
4006 /* The +5 is so we can append "\\*.*\0" */
4007 wnamebuf = PyMem_New(wchar_t, len + 5);
4008 if (!wnamebuf) {
4009 PyErr_NoMemory();
4010 goto exit;
4011 }
4012 wcscpy(wnamebuf, po_wchars);
4013 if (len > 0) {
4014 wchar_t wch = wnamebuf[len-1];
4015 if (wch != SEP && wch != ALTSEP && wch != L':')
4016 wnamebuf[len++] = SEP;
4017 wcscpy(wnamebuf + len, L"*.*");
4018 }
4019 if ((list = PyList_New(0)) == NULL) {
4020 goto exit;
4021 }
4022 Py_BEGIN_ALLOW_THREADS
4023 hFindFile = FindFirstFileW(wnamebuf, &wFileData);
4024 Py_END_ALLOW_THREADS
4025 if (hFindFile == INVALID_HANDLE_VALUE) {
4026 int error = GetLastError();
4027 if (error == ERROR_FILE_NOT_FOUND)
4028 goto exit;
4029 Py_DECREF(list);
4030 list = path_error(path);
4031 goto exit;
4032 }
4033 do {
4034 /* Skip over . and .. */
4035 if (wcscmp(wFileData.cFileName, L".") != 0 &&
4036 wcscmp(wFileData.cFileName, L"..") != 0) {
4037 v = PyUnicode_FromWideChar(wFileData.cFileName,
4038 wcslen(wFileData.cFileName));
4039 if (path->narrow && v) {
4040 Py_SETREF(v, PyUnicode_EncodeFSDefault(v));
4041 }
4042 if (v == NULL) {
4043 Py_DECREF(list);
4044 list = NULL;
4045 break;
4046 }
4047 if (PyList_Append(list, v) != 0) {
4048 Py_DECREF(v);
4049 Py_DECREF(list);
4050 list = NULL;
4051 break;
4052 }
4053 Py_DECREF(v);
4054 }
4055 Py_BEGIN_ALLOW_THREADS
4056 result = FindNextFileW(hFindFile, &wFileData);
4057 Py_END_ALLOW_THREADS
4058 /* FindNextFile sets error to ERROR_NO_MORE_FILES if
4059 it got to the end of the directory. */
4060 if (!result && GetLastError() != ERROR_NO_MORE_FILES) {
4061 Py_DECREF(list);
4062 list = path_error(path);
4063 goto exit;
4064 }
4065 } while (result == TRUE);
4066
4067 exit:
4068 if (hFindFile != INVALID_HANDLE_VALUE) {
4069 if (FindClose(hFindFile) == FALSE) {
4070 if (list != NULL) {
4071 Py_DECREF(list);
4072 list = path_error(path);
4073 }
4074 }
4075 }
4076 PyMem_Free(wnamebuf);
4077
4078 return list;
4079 } /* end of _listdir_windows_no_opendir */
4080
4081 #else /* thus POSIX, ie: not (MS_WINDOWS and not HAVE_OPENDIR) */
4082
4083 static PyObject *
4084 108251 _posix_listdir(path_t *path, PyObject *list)
4085 {
4086 PyObject *v;
4087 108251 DIR *dirp = NULL;
4088 struct dirent *ep;
4089 int return_str; /* if false, return bytes */
4090 #ifdef HAVE_FDOPENDIR
4091 108251 int fd = -1;
4092 #endif
4093
4094 108251 errno = 0;
4095 #ifdef HAVE_FDOPENDIR
4096
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 108251 times.
108251 if (path->fd != -1) {
4097 if (HAVE_FDOPENDIR_RUNTIME) {
4098 /* closedir() closes the FD, so we duplicate it */
4099 fd = _Py_dup(path->fd);
4100 if (fd == -1)
4101 return NULL;
4102
4103 return_str = 1;
4104
4105 Py_BEGIN_ALLOW_THREADS
4106 dirp = fdopendir(fd);
4107 Py_END_ALLOW_THREADS
4108 } else {
4109 PyErr_SetString(PyExc_TypeError,
4110 "listdir: path should be string, bytes, os.PathLike or None, not int");
4111 return NULL;
4112 }
4113 }
4114 else
4115 #endif
4116 {
4117 const char *name;
4118
1/2
✓ Branch 0 taken 108251 times.
✗ Branch 1 not taken.
108251 if (path->narrow) {
4119 108251 name = path->narrow;
4120 /* only return bytes if they specified a bytes-like object */
4121 108251 return_str = !PyObject_CheckBuffer(path->object);
4122 }
4123 else {
4124 name = ".";
4125 return_str = 1;
4126 }
4127
4128 108251 Py_BEGIN_ALLOW_THREADS
4129 108251 dirp = opendir(name);
4130 108251 Py_END_ALLOW_THREADS
4131 }
4132
4133
2/2
✓ Branch 0 taken 29876 times.
✓ Branch 1 taken 78375 times.
108251 if (dirp == NULL) {
4134 29876 list = path_error(path);
4135 #ifdef HAVE_FDOPENDIR
4136
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29876 times.
29876 if (fd != -1) {
4137 Py_BEGIN_ALLOW_THREADS
4138 close(fd);
4139 Py_END_ALLOW_THREADS
4140 }
4141 #endif
4142 29876 goto exit;
4143 }
4144
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 78375 times.
78375 if ((list = PyList_New(0)) == NULL) {
4145 goto exit;
4146 }
4147 for (;;) {
4148 3429689 errno = 0;
4149 3429689 Py_BEGIN_ALLOW_THREADS
4150 3429689 ep = readdir(dirp);
4151 3429689 Py_END_ALLOW_THREADS
4152
2/2
✓ Branch 0 taken 78375 times.
✓ Branch 1 taken 3351314 times.
3429689 if (ep == NULL) {
4153
1/2
✓ Branch 0 taken 78375 times.
✗ Branch 1 not taken.
78375 if (errno == 0) {
4154 78375 break;
4155 } else {
4156 Py_DECREF(list);
4157 list = path_error(path);
4158 goto exit;
4159 }
4160 }
4161
2/2
✓ Branch 0 taken 159928 times.
✓ Branch 1 taken 3191386 times.
3351314 if (ep->d_name[0] == '.' &&
4162
2/2
✓ Branch 0 taken 81553 times.
✓ Branch 1 taken 78375 times.
159928 (NAMLEN(ep) == 1 ||
4163
3/4
✓ Branch 0 taken 78375 times.
✓ Branch 1 taken 3178 times.
✓ Branch 2 taken 78375 times.
✗ Branch 3 not taken.
81553 (ep->d_name[1] == '.' && NAMLEN(ep) == 2)))
4164 156750 continue;
4165
1/2
✓ Branch 0 taken 3194564 times.
✗ Branch 1 not taken.
3194564 if (return_str)
4166 3194564 v = PyUnicode_DecodeFSDefaultAndSize(ep->d_name, NAMLEN(ep));
4167 else
4168 v = PyBytes_FromStringAndSize(ep->d_name, NAMLEN(ep));
4169
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3194564 times.
3194564 if (v == NULL) {
4170 Py_CLEAR(list);
4171 break;
4172 }
4173
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3194564 times.
3194564 if (PyList_Append(list, v) != 0) {
4174 Py_DECREF(v);
4175 Py_CLEAR(list);
4176 break;
4177 }
4178 3194564 Py_DECREF(v);
4179 }
4180
4181 108251 exit:
4182
2/2
✓ Branch 0 taken 78375 times.
✓ Branch 1 taken 29876 times.
108251 if (dirp != NULL) {
4183 78375 Py_BEGIN_ALLOW_THREADS
4184 #ifdef HAVE_FDOPENDIR
4185
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 78375 times.
78375 if (fd > -1)
4186 rewinddir(dirp);
4187 #endif
4188 78375 closedir(dirp);
4189 78375 Py_END_ALLOW_THREADS
4190 }
4191
4192 108251 return list;
4193 } /* end of _posix_listdir */
4194 #endif /* which OS */
4195
4196
4197 /*[clinic input]
4198 os.listdir
4199
4200 path : path_t(nullable=True, allow_fd='PATH_HAVE_FDOPENDIR') = None
4201
4202 Return a list containing the names of the files in the directory.
4203
4204 path can be specified as either str, bytes, or a path-like object. If path is bytes,
4205 the filenames returned will also be bytes; in all other circumstances
4206 the filenames returned will be str.
4207 If path is None, uses the path='.'.
4208 On some platforms, path may also be specified as an open file descriptor;\
4209 the file descriptor must refer to a directory.
4210 If this functionality is unavailable, using it raises NotImplementedError.
4211
4212 The list is in arbitrary order. It does not include the special
4213 entries '.' and '..' even if they are present in the directory.
4214
4215
4216 [clinic start generated code]*/
4217
4218 static PyObject *
4219 108251 os_listdir_impl(PyObject *module, path_t *path)
4220 /*[clinic end generated code: output=293045673fcd1a75 input=e3f58030f538295d]*/
4221 {
4222
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 108251 times.
108251 if (PySys_Audit("os.listdir", "O",
4223
1/2
✓ Branch 0 taken 108251 times.
✗ Branch 1 not taken.
108251 path->object ? path->object : Py_None) < 0) {
4224 return NULL;
4225 }
4226 #if defined(MS_WINDOWS) && !defined(HAVE_OPENDIR)
4227 return _listdir_windows_no_opendir(path, NULL);
4228 #else
4229 108251 return _posix_listdir(path, NULL);
4230 #endif
4231 }
4232
4233 #ifdef MS_WINDOWS
4234 int
4235 _PyOS_getfullpathname(const wchar_t *path, wchar_t **abspath_p)
4236 {
4237 wchar_t woutbuf[MAX_PATH], *woutbufp = woutbuf;
4238 DWORD result;
4239
4240 result = GetFullPathNameW(path,
4241 Py_ARRAY_LENGTH(woutbuf), woutbuf,
4242 NULL);
4243 if (!result) {
4244 return -1;
4245 }
4246
4247 if (result >= Py_ARRAY_LENGTH(woutbuf)) {
4248 if ((size_t)result <= (size_t)PY_SSIZE_T_MAX / sizeof(wchar_t)) {
4249 woutbufp = PyMem_RawMalloc((size_t)result * sizeof(wchar_t));
4250 }
4251 else {
4252 woutbufp = NULL;
4253 }
4254 if (!woutbufp) {
4255 *abspath_p = NULL;
4256 return 0;
4257 }
4258
4259 result = GetFullPathNameW(path, result, woutbufp, NULL);
4260 if (!result) {
4261 PyMem_RawFree(woutbufp);
4262 return -1;
4263 }
4264 }
4265
4266 if (woutbufp != woutbuf) {
4267 *abspath_p = woutbufp;
4268 return 0;
4269 }
4270
4271 *abspath_p = _PyMem_RawWcsdup(woutbufp);
4272 return 0;
4273 }
4274
4275
4276 /* A helper function for abspath on win32 */
4277 /*[clinic input]
4278 os._getfullpathname
4279
4280 path: path_t
4281 /
4282
4283 [clinic start generated code]*/
4284
4285 static PyObject *
4286 os__getfullpathname_impl(PyObject *module, path_t *path)
4287 /*[clinic end generated code: output=bb8679d56845bc9b input=332ed537c29d0a3e]*/
4288 {
4289 wchar_t *abspath;
4290
4291 if (_PyOS_getfullpathname(path->wide, &abspath) < 0) {
4292 return win32_error_object("GetFullPathNameW", path->object);
4293 }
4294 if (abspath == NULL) {
4295 return PyErr_NoMemory();
4296 }
4297
4298 PyObject *str = PyUnicode_FromWideChar(abspath, wcslen(abspath));
4299 PyMem_RawFree(abspath);
4300 if (str == NULL) {
4301 return NULL;
4302 }
4303 if (path->narrow) {
4304 Py_SETREF(str, PyUnicode_EncodeFSDefault(str));
4305 }
4306 return str;
4307 }
4308
4309
4310 /*[clinic input]
4311 os._getfinalpathname
4312
4313 path: path_t
4314 /
4315
4316 A helper function for samepath on windows.
4317 [clinic start generated code]*/
4318
4319 static PyObject *
4320 os__getfinalpathname_impl(PyObject *module, path_t *path)
4321 /*[clinic end generated code: output=621a3c79bc29ebfa input=2b6b6c7cbad5fb84]*/
4322 {
4323 HANDLE hFile;
4324 wchar_t buf[MAXPATHLEN], *target_path = buf;
4325 int buf_size = Py_ARRAY_LENGTH(buf);
4326 int result_length;
4327 PyObject *result;
4328
4329 Py_BEGIN_ALLOW_THREADS
4330 hFile = CreateFileW(
4331 path->wide,
4332 0, /* desired access */
4333 0, /* share mode */
4334 NULL, /* security attributes */
4335 OPEN_EXISTING,
4336 /* FILE_FLAG_BACKUP_SEMANTICS is required to open a directory */
4337 FILE_FLAG_BACKUP_SEMANTICS,
4338 NULL);
4339 Py_END_ALLOW_THREADS
4340
4341 if (hFile == INVALID_HANDLE_VALUE) {
4342 return win32_error_object("CreateFileW", path->object);
4343 }
4344
4345 /* We have a good handle to the target, use it to determine the
4346 target path name. */
4347 while (1) {
4348 Py_BEGIN_ALLOW_THREADS
4349 result_length = GetFinalPathNameByHandleW(hFile, target_path,
4350 buf_size, VOLUME_NAME_DOS);
4351 Py_END_ALLOW_THREADS
4352
4353 if (!result_length) {
4354 result = win32_error_object("GetFinalPathNameByHandleW",
4355 path->object);
4356 goto cleanup;
4357 }
4358
4359 if (result_length < buf_size) {
4360 break;
4361 }
4362
4363 wchar_t *tmp;
4364 tmp = PyMem_Realloc(target_path != buf ? target_path : NULL,
4365 result_length * sizeof(*tmp));
4366 if (!tmp) {
4367 result = PyErr_NoMemory();
4368 goto cleanup;
4369 }
4370
4371 buf_size = result_length;
4372 target_path = tmp;
4373 }
4374
4375 result = PyUnicode_FromWideChar(target_path, result_length);
4376 if (result && path->narrow) {
4377 Py_SETREF(result, PyUnicode_EncodeFSDefault(result));
4378 }
4379
4380 cleanup:
4381 if (target_path != buf) {
4382 PyMem_Free(target_path);
4383 }
4384 CloseHandle(hFile);
4385 return result;
4386 }
4387
4388
4389 /*[clinic input]
4390 os._getvolumepathname
4391
4392 path: path_t
4393
4394 A helper function for ismount on Win32.
4395 [clinic start generated code]*/
4396
4397 static PyObject *
4398 os__getvolumepathname_impl(PyObject *module, path_t *path)
4399 /*[clinic end generated code: output=804c63fd13a1330b input=722b40565fa21552]*/
4400 {
4401 PyObject *result;
4402 wchar_t *mountpath=NULL;
4403 size_t buflen;
4404 BOOL ret;
4405
4406 /* Volume path should be shorter than entire path */
4407 buflen = Py_MAX(path->length, MAX_PATH);
4408
4409 if (buflen > PY_DWORD_MAX) {
4410 PyErr_SetString(PyExc_OverflowError, "path too long");
4411 return NULL;
4412 }
4413
4414 mountpath = PyMem_New(wchar_t, buflen);
4415 if (mountpath == NULL)
4416 return PyErr_NoMemory();
4417
4418 Py_BEGIN_ALLOW_THREADS
4419 ret = GetVolumePathNameW(path->wide, mountpath,
4420 Py_SAFE_DOWNCAST(buflen, size_t, DWORD));
4421 Py_END_ALLOW_THREADS
4422
4423 if (!ret) {
4424 result = win32_error_object("_getvolumepathname", path->object);
4425 goto exit;
4426 }
4427 result = PyUnicode_FromWideChar(mountpath, wcslen(mountpath));
4428 if (path->narrow)
4429 Py_SETREF(result, PyUnicode_EncodeFSDefault(result));
4430
4431 exit:
4432 PyMem_Free(mountpath);
4433 return result;
4434 }
4435
4436
4437 /*[clinic input]
4438 os._path_splitroot
4439
4440 path: path_t
4441
4442 Removes everything after the root on Win32.
4443 [clinic start generated code]*/
4444
4445 static PyObject *
4446 os__path_splitroot_impl(PyObject *module, path_t *path)
4447 /*[clinic end generated code: output=ab7f1a88b654581c input=dc93b1d3984cffb6]*/
4448 {
4449 wchar_t *buffer;
4450 wchar_t *end;
4451 PyObject *result = NULL;
4452 HRESULT ret;
4453
4454 buffer = (wchar_t*)PyMem_Malloc(sizeof(wchar_t) * (wcslen(path->wide) + 1));
4455 if (!buffer) {
4456 return NULL;
4457 }
4458 wcscpy(buffer, path->wide);
4459 for (wchar_t *p = wcschr(buffer, L'/'); p; p = wcschr(p, L'/')) {
4460 *p = L'\\';
4461 }
4462
4463 Py_BEGIN_ALLOW_THREADS
4464 ret = PathCchSkipRoot(buffer, &end);
4465 Py_END_ALLOW_THREADS
4466 if (FAILED(ret)) {
4467 result = Py_BuildValue("sO", "", path->object);
4468 } else if (end != buffer) {
4469 size_t rootLen = (size_t)(end - buffer);
4470 result = Py_BuildValue("NN",
4471 PyUnicode_FromWideChar(path->wide, rootLen),
4472 PyUnicode_FromWideChar(path->wide + rootLen, -1)
4473 );
4474 } else {
4475 result = Py_BuildValue("Os", path->object, "");
4476 }
4477 PyMem_Free(buffer);
4478
4479 return result;
4480 }
4481
4482
4483 #endif /* MS_WINDOWS */
4484
4485
4486 /*[clinic input]
4487 os._path_normpath
4488
4489 path: object
4490
4491 Basic path normalization.
4492 [clinic start generated code]*/
4493
4494 static PyObject *
4495 115312 os__path_normpath_impl(PyObject *module, PyObject *path)
4496 /*[clinic end generated code: output=b94d696d828019da input=5e90c39e12549dc0]*/
4497 {
4498
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 115312 times.
115312 if (!PyUnicode_Check(path)) {
4499 PyErr_Format(PyExc_TypeError, "expected 'str', not '%.200s'",
4500 Py_TYPE(path)->tp_name);
4501 return NULL;
4502 }
4503 Py_ssize_t len;
4504 115312 wchar_t *buffer = PyUnicode_AsWideCharString(path, &len);
4505
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 115312 times.
115312 if (!buffer) {
4506 return NULL;
4507 }
4508 115312 PyObject *result = PyUnicode_FromWideChar(_Py_normpath(buffer, len), -1);
4509 115312 PyMem_Free(buffer);
4510 115312 return result;
4511 }
4512
4513 /*[clinic input]
4514 os.mkdir
4515
4516 path : path_t
4517
4518 mode: int = 0o777
4519
4520 *
4521
4522 dir_fd : dir_fd(requires='mkdirat') = None
4523
4524 # "mkdir(path, mode=0o777, *, dir_fd=None)\n\n\
4525
4526 Create a directory.
4527
4528 If dir_fd is not None, it should be a file descriptor open to a directory,
4529 and path should be relative; path will then be relative to that directory.
4530 dir_fd may not be implemented on your platform.
4531 If it is unavailable, using it will raise a NotImplementedError.
4532
4533 The mode argument is ignored on Windows.
4534 [clinic start generated code]*/
4535
4536 static PyObject *
4537 16219 os_mkdir_impl(PyObject *module, path_t *path, int mode, int dir_fd)
4538 /*[clinic end generated code: output=a70446903abe821f input=e965f68377e9b1ce]*/
4539 {
4540 int result;
4541 #ifdef HAVE_MKDIRAT
4542 16219 int mkdirat_unavailable = 0;
4543 #endif
4544
4545
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 16219 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 16219 times.
16219 if (PySys_Audit("os.mkdir", "Oii", path->object, mode,
4546 dir_fd == DEFAULT_DIR_FD ? -1 : dir_fd) < 0) {
4547 return NULL;
4548 }
4549
4550 #ifdef MS_WINDOWS
4551 Py_BEGIN_ALLOW_THREADS
4552 result = CreateDirectoryW(path->wide, NULL);
4553 Py_END_ALLOW_THREADS
4554
4555 if (!result)
4556 return path_error(path);
4557 #else
4558 16219 Py_BEGIN_ALLOW_THREADS
4559 #if HAVE_MKDIRAT
4560
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16219 times.
16219 if (dir_fd != DEFAULT_DIR_FD) {
4561 if (HAVE_MKDIRAT_RUNTIME) {
4562 result = mkdirat(dir_fd, path->narrow, mode);
4563
4564 } else {
4565 mkdirat_unavailable = 1;
4566 }
4567 } else
4568 #endif
4569 #if defined(__WATCOMC__) && !defined(__QNX__)
4570 result = mkdir(path->narrow);
4571 #else
4572 16219 result = mkdir(path->narrow, mode);
4573 #endif
4574 16219 Py_END_ALLOW_THREADS
4575
4576 #if HAVE_MKDIRAT
4577
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16219 times.
16219 if (mkdirat_unavailable) {
4578 argument_unavailable_error(NULL, "dir_fd");
4579 return NULL;
4580 }
4581 #endif
4582
4583
2/2
✓ Branch 0 taken 11474 times.
✓ Branch 1 taken 4745 times.
16219 if (result < 0)
4584 11474 return path_error(path);
4585 #endif /* MS_WINDOWS */
4586 4745 Py_RETURN_NONE;
4587 }
4588
4589
4590 /* sys/resource.h is needed for at least: wait3(), wait4(), broken nice. */
4591 #if defined(HAVE_SYS_RESOURCE_H)
4592 #include <sys/resource.h>
4593 #endif
4594
4595
4596 #ifdef HAVE_NICE
4597 /*[clinic input]
4598 os.nice
4599
4600 increment: int
4601 /
4602
4603 Add increment to the priority of process and return the new priority.
4604 [clinic start generated code]*/
4605
4606 static PyObject *
4607 os_nice_impl(PyObject *module, int increment)
4608 /*[clinic end generated code: output=9dad8a9da8109943 input=864be2d402a21da2]*/
4609 {
4610 int value;
4611
4612 /* There are two flavours of 'nice': one that returns the new
4613 priority (as required by almost all standards out there) and the
4614 Linux/FreeBSD one, which returns '0' on success and advices
4615 the use of getpriority() to get the new priority.
4616
4617 If we are of the nice family that returns the new priority, we
4618 need to clear errno before the call, and check if errno is filled
4619 before calling posix_error() on a returnvalue of -1, because the
4620 -1 may be the actual new priority! */
4621
4622 errno = 0;
4623 value = nice(increment);
4624 #if defined(HAVE_BROKEN_NICE) && defined(HAVE_GETPRIORITY)
4625 if (value == 0)
4626 value = getpriority(PRIO_PROCESS, 0);
4627 #endif
4628 if (value == -1 && errno != 0)
4629 /* either nice() or getpriority() returned an error */
4630 return posix_error();
4631 return PyLong_FromLong((long) value);
4632 }
4633 #endif /* HAVE_NICE */
4634
4635
4636 #ifdef HAVE_GETPRIORITY
4637 /*[clinic input]
4638 os.getpriority
4639
4640 which: int
4641 who: int
4642
4643 Return program scheduling priority.
4644 [clinic start generated code]*/
4645
4646 static PyObject *
4647 os_getpriority_impl(PyObject *module, int which, int who)
4648 /*[clinic end generated code: output=c41b7b63c7420228 input=9be615d40e2544ef]*/
4649 {
4650 int retval;
4651
4652 errno = 0;
4653 retval = getpriority(which, who);
4654 if (errno != 0)
4655 return posix_error();
4656 return PyLong_FromLong((long)retval);
4657 }
4658 #endif /* HAVE_GETPRIORITY */
4659
4660
4661 #ifdef HAVE_SETPRIORITY
4662 /*[clinic input]
4663 os.setpriority
4664
4665 which: int
4666 who: int
4667 priority: int
4668
4669 Set program scheduling priority.
4670 [clinic start generated code]*/
4671
4672 static PyObject *
4673 os_setpriority_impl(PyObject *module, int which, int who, int priority)
4674 /*[clinic end generated code: output=3d910d95a7771eb2 input=710ccbf65b9dc513]*/
4675 {
4676 int retval;
4677
4678 retval = setpriority(which, who, priority);
4679 if (retval == -1)
4680 return posix_error();
4681 Py_RETURN_NONE;
4682 }
4683 #endif /* HAVE_SETPRIORITY */
4684
4685
4686 static PyObject *
4687 4488 internal_rename(path_t *src, path_t *dst, int src_dir_fd, int dst_dir_fd, int is_replace)
4688 {
4689
2/2
✓ Branch 0 taken 4472 times.
✓ Branch 1 taken 16 times.
4488 const char *function_name = is_replace ? "replace" : "rename";
4690 int dir_fd_specified;
4691
4692 #ifdef HAVE_RENAMEAT
4693 4488 int renameat_unavailable = 0;
4694 #endif
4695
4696 #ifdef MS_WINDOWS
4697 BOOL result;
4698 int flags = is_replace ? MOVEFILE_REPLACE_EXISTING : 0;
4699 #else
4700 int result;
4701 #endif
4702
4703
2/4
✓ Branch 0 taken 4488 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4488 times.
4488 dir_fd_specified = (src_dir_fd != DEFAULT_DIR_FD) ||
4704 (dst_dir_fd != DEFAULT_DIR_FD);
4705 #ifndef HAVE_RENAMEAT
4706 if (dir_fd_specified) {
4707 argument_unavailable_error(function_name, "src_dir_fd and dst_dir_fd");
4708 return NULL;
4709 }
4710 #endif
4711
4712
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 4488 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4488 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4488 times.
4488 if (PySys_Audit("os.rename", "OOii", src->object, dst->object,
4713 src_dir_fd == DEFAULT_DIR_FD ? -1 : src_dir_fd,
4714 dst_dir_fd == DEFAULT_DIR_FD ? -1 : dst_dir_fd) < 0) {
4715 return NULL;
4716 }
4717
4718 #ifdef MS_WINDOWS
4719 Py_BEGIN_ALLOW_THREADS
4720 result = MoveFileExW(src->wide, dst->wide, flags);
4721 Py_END_ALLOW_THREADS
4722
4723 if (!result)
4724 return path_error2(src, dst);
4725
4726 #else
4727
3/8
✓ Branch 0 taken 4488 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4488 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4488 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
4488 if ((src->narrow && dst->wide) || (src->wide && dst->narrow)) {
4728 PyErr_Format(PyExc_ValueError,
4729 "%s: src and dst must be the same type", function_name);
4730 return NULL;
4731 }
4732
4733 4488 Py_BEGIN_ALLOW_THREADS
4734 #ifdef HAVE_RENAMEAT
4735
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4488 times.
4488 if (dir_fd_specified) {
4736 if (HAVE_RENAMEAT_RUNTIME) {
4737 result = renameat(src_dir_fd, src->narrow, dst_dir_fd, dst->narrow);
4738 } else {
4739 renameat_unavailable = 1;
4740 }
4741 } else
4742 #endif
4743 4488 result = rename(src->narrow, dst->narrow);
4744 4488 Py_END_ALLOW_THREADS
4745
4746
4747 #ifdef HAVE_RENAMEAT
4748
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4488 times.
4488 if (renameat_unavailable) {
4749 argument_unavailable_error(function_name, "src_dir_fd and dst_dir_fd");
4750 return NULL;
4751 }
4752 #endif
4753
4754
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4488 times.
4488 if (result)
4755 return path_error2(src, dst);
4756 #endif
4757 4488 Py_RETURN_NONE;
4758 }
4759
4760
4761 /*[clinic input]
4762 os.rename
4763
4764 src : path_t
4765 dst : path_t
4766 *
4767 src_dir_fd : dir_fd = None
4768 dst_dir_fd : dir_fd = None
4769
4770 Rename a file or directory.
4771
4772 If either src_dir_fd or dst_dir_fd is not None, it should be a file
4773 descriptor open to a directory, and the respective path string (src or dst)
4774 should be relative; the path will then be relative to that directory.
4775 src_dir_fd and dst_dir_fd, may not be implemented on your platform.
4776 If they are unavailable, using them will raise a NotImplementedError.
4777 [clinic start generated code]*/
4778
4779 static PyObject *
4780 16 os_rename_impl(PyObject *module, path_t *src, path_t *dst, int src_dir_fd,
4781 int dst_dir_fd)
4782 /*[clinic end generated code: output=59e803072cf41230 input=faa61c847912c850]*/
4783 {
4784 16 return internal_rename(src, dst, src_dir_fd, dst_dir_fd, 0);
4785 }
4786
4787
4788 /*[clinic input]
4789 os.replace = os.rename
4790
4791 Rename a file or directory, overwriting the destination.
4792
4793 If either src_dir_fd or dst_dir_fd is not None, it should be a file
4794 descriptor open to a directory, and the respective path string (src or dst)
4795 should be relative; the path will then be relative to that directory.
4796 src_dir_fd and dst_dir_fd, may not be implemented on your platform.
4797 If they are unavailable, using them will raise a NotImplementedError.
4798 [clinic start generated code]*/
4799
4800 static PyObject *
4801 4472 os_replace_impl(PyObject *module, path_t *src, path_t *dst, int src_dir_fd,
4802 int dst_dir_fd)
4803 /*[clinic end generated code: output=1968c02e7857422b input=c003f0def43378ef]*/
4804 {
4805 4472 return internal_rename(src, dst, src_dir_fd, dst_dir_fd, 1);
4806 }
4807
4808
4809 /*[clinic input]
4810 os.rmdir
4811
4812 path: path_t
4813 *
4814 dir_fd: dir_fd(requires='unlinkat') = None
4815
4816 Remove a directory.
4817
4818 If dir_fd is not None, it should be a file descriptor open to a directory,
4819 and path should be relative; path will then be relative to that directory.
4820 dir_fd may not be implemented on your platform.
4821 If it is unavailable, using it will raise a NotImplementedError.
4822 [clinic start generated code]*/
4823
4824 static PyObject *
4825 1273 os_rmdir_impl(PyObject *module, path_t *path, int dir_fd)
4826 /*[clinic end generated code: output=080eb54f506e8301 input=38c8b375ca34a7e2]*/
4827 {
4828 int result;
4829 #ifdef HAVE_UNLINKAT
4830 1273 int unlinkat_unavailable = 0;
4831 #endif
4832
4833
3/4
✓ Branch 0 taken 712 times.
✓ Branch 1 taken 561 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1273 times.
1273 if (PySys_Audit("os.rmdir", "Oi", path->object,
4834 dir_fd == DEFAULT_DIR_FD ? -1 : dir_fd) < 0) {
4835 return NULL;
4836 }
4837
4838 1273 Py_BEGIN_ALLOW_THREADS
4839 #ifdef MS_WINDOWS
4840 /* Windows, success=1, UNIX, success=0 */
4841 result = !RemoveDirectoryW(path->wide);
4842 #else
4843 #ifdef HAVE_UNLINKAT
4844
2/2
✓ Branch 0 taken 712 times.
✓ Branch 1 taken 561 times.
1273 if (dir_fd != DEFAULT_DIR_FD) {
4845 if (HAVE_UNLINKAT_RUNTIME) {
4846 712 result = unlinkat(dir_fd, path->narrow, AT_REMOVEDIR);
4847 } else {
4848 unlinkat_unavailable = 1;
4849 result = -1;
4850 }
4851 } else
4852 #endif
4853 561 result = rmdir(path->narrow);
4854 #endif
4855 1273 Py_END_ALLOW_THREADS
4856
4857 #ifdef HAVE_UNLINKAT
4858
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1273 times.
1273 if (unlinkat_unavailable) {
4859 argument_unavailable_error("rmdir", "dir_fd");
4860 return NULL;
4861 }
4862 #endif
4863
4864
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1272 times.
1273 if (result)
4865 1 return path_error(path);
4866
4867 1272 Py_RETURN_NONE;
4868 }
4869
4870
4871 #ifdef HAVE_SYSTEM
4872 #ifdef MS_WINDOWS
4873 /*[clinic input]
4874 os.system -> long
4875
4876 command: Py_UNICODE
4877
4878 Execute the command in a subshell.
4879 [clinic start generated code]*/
4880
4881 static long
4882 os_system_impl(PyObject *module, const Py_UNICODE *command)
4883 /*[clinic end generated code: output=5b7c3599c068ca42 input=303f5ce97df606b0]*/
4884 {
4885 long result;
4886
4887 if (PySys_Audit("os.system", "(u)", command) < 0) {
4888 return -1;
4889 }
4890
4891 Py_BEGIN_ALLOW_THREADS
4892 _Py_BEGIN_SUPPRESS_IPH
4893 result = _wsystem(command);
4894 _Py_END_SUPPRESS_IPH
4895 Py_END_ALLOW_THREADS
4896 return result;
4897 }
4898 #else /* MS_WINDOWS */
4899 /*[clinic input]
4900 os.system -> long
4901
4902 command: FSConverter
4903
4904 Execute the command in a subshell.
4905 [clinic start generated code]*/
4906
4907 static long
4908 2 os_system_impl(PyObject *module, PyObject *command)
4909 /*[clinic end generated code: output=290fc437dd4f33a0 input=86a58554ba6094af]*/
4910 {
4911 long result;
4912 2 const char *bytes = PyBytes_AsString(command);
4913
4914
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (PySys_Audit("os.system", "(O)", command) < 0) {
4915 return -1;
4916 }
4917
4918 2 Py_BEGIN_ALLOW_THREADS
4919 2 result = system(bytes);
4920 2 Py_END_ALLOW_THREADS
4921 2 return result;
4922 }
4923 #endif
4924 #endif /* HAVE_SYSTEM */
4925
4926
4927 #ifdef HAVE_UMASK
4928 /*[clinic input]
4929 os.umask
4930
4931 mask: int
4932 /
4933
4934 Set the current numeric umask and return the previous umask.
4935 [clinic start generated code]*/
4936
4937 static PyObject *
4938 148 os_umask_impl(PyObject *module, int mask)
4939 /*[clinic end generated code: output=a2e33ce3bc1a6e33 input=ab6bfd9b24d8a7e8]*/
4940 {
4941 148 int i = (int)umask(mask);
4942
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 148 times.
148 if (i < 0)
4943 return posix_error();
4944 148 return PyLong_FromLong((long)i);
4945 }
4946 #endif
4947
4948 #ifdef MS_WINDOWS
4949
4950 /* override the default DeleteFileW behavior so that directory
4951 symlinks can be removed with this function, the same as with
4952 Unix symlinks */
4953 BOOL WINAPI Py_DeleteFileW(LPCWSTR lpFileName)
4954 {
4955 WIN32_FILE_ATTRIBUTE_DATA info;
4956 WIN32_FIND_DATAW find_data;
4957 HANDLE find_data_handle;
4958 int is_directory = 0;
4959 int is_link = 0;
4960
4961 if (GetFileAttributesExW(lpFileName, GetFileExInfoStandard, &info)) {
4962 is_directory = info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
4963
4964 /* Get WIN32_FIND_DATA structure for the path to determine if
4965 it is a symlink */
4966 if(is_directory &&
4967 info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
4968 find_data_handle = FindFirstFileW(lpFileName, &find_data);
4969
4970 if(find_data_handle != INVALID_HANDLE_VALUE) {
4971 /* IO_REPARSE_TAG_SYMLINK if it is a symlink and
4972 IO_REPARSE_TAG_MOUNT_POINT if it is a junction point. */
4973 is_link = find_data.dwReserved0 == IO_REPARSE_TAG_SYMLINK ||
4974 find_data.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT;
4975 FindClose(find_data_handle);
4976 }
4977 }
4978 }
4979
4980 if (is_directory && is_link)
4981 return RemoveDirectoryW(lpFileName);
4982
4983 return DeleteFileW(lpFileName);
4984 }
4985 #endif /* MS_WINDOWS */
4986
4987
4988 /*[clinic input]
4989 os.unlink
4990
4991 path: path_t
4992 *
4993 dir_fd: dir_fd(requires='unlinkat')=None
4994
4995 Remove a file (same as remove()).
4996
4997 If dir_fd is not None, it should be a file descriptor open to a directory,
4998 and path should be relative; path will then be relative to that directory.
4999 dir_fd may not be implemented on your platform.
5000 If it is unavailable, using it will raise a NotImplementedError.
5001
5002 [clinic start generated code]*/
5003
5004 static PyObject *
5005 48432 os_unlink_impl(PyObject *module, path_t *path, int dir_fd)
5006 /*[clinic end generated code: output=621797807b9963b1 input=d7bcde2b1b2a2552]*/
5007 {
5008 int result;
5009 #ifdef HAVE_UNLINKAT
5010 48432 int unlinkat_unavailable = 0;
5011 #endif
5012
5013
3/4
✓ Branch 0 taken 47832 times.
✓ Branch 1 taken 600 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 48432 times.
48432 if (PySys_Audit("os.remove", "Oi", path->object,
5014 dir_fd == DEFAULT_DIR_FD ? -1 : dir_fd) < 0) {
5015 return NULL;
5016 }
5017
5018 48432 Py_BEGIN_ALLOW_THREADS
5019 _Py_BEGIN_SUPPRESS_IPH
5020 #ifdef MS_WINDOWS
5021 /* Windows, success=1, UNIX, success=0 */
5022 result = !Py_DeleteFileW(path->wide);
5023 #else
5024 #ifdef HAVE_UNLINKAT
5025
2/2
✓ Branch 0 taken 47832 times.
✓ Branch 1 taken 600 times.
48432 if (dir_fd != DEFAULT_DIR_FD) {
5026 if (HAVE_UNLINKAT_RUNTIME) {
5027
5028 47832 result = unlinkat(dir_fd, path->narrow, 0);
5029 } else {
5030 unlinkat_unavailable = 1;
5031 }
5032 } else
5033 #endif /* HAVE_UNLINKAT */
5034 600 result = unlink(path->narrow);
5035 #endif
5036 _Py_END_SUPPRESS_IPH
5037 48432 Py_END_ALLOW_THREADS
5038
5039 #ifdef HAVE_UNLINKAT
5040
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 48432 times.
48432 if (unlinkat_unavailable) {
5041 argument_unavailable_error(NULL, "dir_fd");
5042 return NULL;
5043 }
5044 #endif
5045
5046
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 48432 times.
48432 if (result)
5047 return path_error(path);
5048
5049 48432 Py_RETURN_NONE;
5050 }
5051
5052
5053 /*[clinic input]
5054 os.remove = os.unlink
5055
5056 Remove a file (same as unlink()).
5057
5058 If dir_fd is not None, it should be a file descriptor open to a directory,
5059 and path should be relative; path will then be relative to that directory.
5060 dir_fd may not be implemented on your platform.
5061 If it is unavailable, using it will raise a NotImplementedError.
5062 [clinic start generated code]*/
5063
5064 static PyObject *
5065 1 os_remove_impl(PyObject *module, path_t *path, int dir_fd)
5066 /*[clinic end generated code: output=a8535b28f0068883 input=e05c5ab55cd30983]*/
5067 {
5068 1 return os_unlink_impl(module, path, dir_fd);
5069 }
5070
5071
5072 static PyStructSequence_Field uname_result_fields[] = {
5073 {"sysname", "operating system name"},
5074 {"nodename", "name of machine on network (implementation-defined)"},
5075 {"release", "operating system release"},
5076 {"version", "operating system version"},
5077 {"machine", "hardware identifier"},
5078 {NULL}
5079 };
5080
5081 PyDoc_STRVAR(uname_result__doc__,
5082 "uname_result: Result from os.uname().\n\n\
5083 This object may be accessed either as a tuple of\n\
5084 (sysname, nodename, release, version, machine),\n\
5085 or via the attributes sysname, nodename, release, version, and machine.\n\
5086 \n\
5087 See os.uname for more information.");
5088
5089 static PyStructSequence_Desc uname_result_desc = {
5090 MODNAME ".uname_result", /* name */
5091 uname_result__doc__, /* doc */
5092 uname_result_fields,
5093 5
5094 };
5095
5096 #ifdef HAVE_UNAME
5097 /*[clinic input]
5098 os.uname
5099
5100 Return an object identifying the current operating system.
5101
5102 The object behaves like a named tuple with the following fields:
5103 (sysname, nodename, release, version, machine)
5104
5105 [clinic start generated code]*/
5106
5107 static PyObject *
5108 2252 os_uname_impl(PyObject *module)
5109 /*[clinic end generated code: output=e6a49cf1a1508a19 input=e68bd246db3043ed]*/
5110 {
5111 struct utsname u;
5112 int res;
5113 PyObject *value;
5114
5115 2252 Py_BEGIN_ALLOW_THREADS
5116 2252 res = uname(&u);
5117 2252 Py_END_ALLOW_THREADS
5118
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2252 times.
2252 if (res < 0)
5119 return posix_error();
5120
5121 2252 PyObject *UnameResultType = get_posix_state(module)->UnameResultType;
5122 2252 value = PyStructSequence_New((PyTypeObject *)UnameResultType);
5123
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2252 times.
2252 if (value == NULL)
5124 return NULL;
5125
5126 #define SET(i, field) \
5127 { \
5128 PyObject *o = PyUnicode_DecodeFSDefault(field); \
5129 if (!o) { \
5130 Py_DECREF(value); \
5131 return NULL; \
5132 } \
5133 PyStructSequence_SET_ITEM(value, i, o); \
5134 } \
5135
5136
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2252 times.
2252 SET(0, u.sysname);
5137
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2252 times.
2252 SET(1, u.nodename);
5138
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2252 times.
2252 SET(2, u.release);
5139
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2252 times.
2252 SET(3, u.version);
5140
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2252 times.
2252 SET(4, u.machine);
5141
5142 #undef SET
5143
5144 2252 return value;
5145 }
5146 #endif /* HAVE_UNAME */
5147
5148
5149
5150 typedef struct {
5151 int now;
5152 time_t atime_s;
5153 long atime_ns;
5154 time_t mtime_s;
5155 long mtime_ns;
5156 } utime_t;
5157
5158 /*
5159 * these macros assume that "ut" is a pointer to a utime_t
5160 * they also intentionally leak the declaration of a pointer named "time"
5161 */
5162 #define UTIME_TO_TIMESPEC \
5163 struct timespec ts[2]; \
5164 struct timespec *time; \
5165 if (ut->now) \
5166 time = NULL; \
5167 else { \
5168 ts[0].tv_sec = ut->atime_s; \
5169 ts[0].tv_nsec = ut->atime_ns; \
5170 ts[1].tv_sec = ut->mtime_s; \
5171 ts[1].tv_nsec = ut->mtime_ns; \
5172 time = ts; \
5173 } \
5174
5175 #define UTIME_TO_TIMEVAL \
5176 struct timeval tv[2]; \
5177 struct timeval *time; \
5178 if (ut->now) \
5179 time = NULL; \
5180 else { \
5181 tv[0].tv_sec = ut->atime_s; \
5182 tv[0].tv_usec = ut->atime_ns / 1000; \
5183 tv[1].tv_sec = ut->mtime_s; \
5184 tv[1].tv_usec = ut->mtime_ns / 1000; \
5185 time = tv; \
5186 } \
5187
5188 #define UTIME_TO_UTIMBUF \
5189 struct utimbuf u; \
5190 struct utimbuf *time; \
5191 if (ut->now) \
5192 time = NULL; \
5193 else { \
5194 u.actime = ut->atime_s; \
5195 u.modtime = ut->mtime_s; \
5196 time = &u; \
5197 }
5198
5199 #define UTIME_TO_TIME_T \
5200 time_t timet[2]; \
5201 time_t *time; \
5202 if (ut->now) \
5203 time = NULL; \
5204 else { \
5205 timet[0] = ut->atime_s; \
5206 timet[1] = ut->mtime_s; \
5207 time = timet; \
5208 } \
5209
5210
5211 #if defined(HAVE_FUTIMESAT) || defined(HAVE_UTIMENSAT)
5212
5213 static int
5214 utime_dir_fd(utime_t *ut, int dir_fd, const char *path, int follow_symlinks)
5215 {
5216 #if defined(__APPLE__) && defined(HAVE_UTIMENSAT)
5217 if (HAVE_UTIMENSAT_RUNTIME) {
5218 int flags = follow_symlinks ? 0 : AT_SYMLINK_NOFOLLOW;
5219 UTIME_TO_TIMESPEC;
5220 return utimensat(dir_fd, path, time, flags);
5221 } else {
5222 errno = ENOSYS;
5223 return -1;
5224 }
5225 #elif defined(HAVE_UTIMENSAT)
5226 int flags = follow_symlinks ? 0 : AT_SYMLINK_NOFOLLOW;
5227 UTIME_TO_TIMESPEC;
5228 return utimensat(dir_fd, path, time, flags);
5229 #elif defined(HAVE_FUTIMESAT)
5230 UTIME_TO_TIMEVAL;
5231 /*
5232 * follow_symlinks will never be false here;
5233 * we only allow !follow_symlinks and dir_fd together
5234 * if we have utimensat()
5235 */
5236 assert(follow_symlinks);
5237 return futimesat(dir_fd, path, time);
5238 #endif
5239 }
5240
5241 #define FUTIMENSAT_DIR_FD_CONVERTER dir_fd_converter
5242 #else
5243 #define FUTIMENSAT_DIR_FD_CONVERTER dir_fd_unavailable
5244 #endif
5245
5246 #if defined(HAVE_FUTIMES) || defined(HAVE_FUTIMENS)
5247
5248 static int
5249 utime_fd(utime_t *ut, int fd)
5250 {
5251 #ifdef HAVE_FUTIMENS
5252
5253 if (HAVE_FUTIMENS_RUNTIME) {
5254
5255 UTIME_TO_TIMESPEC;
5256 return futimens(fd, time);
5257
5258 } else
5259 #ifndef HAVE_FUTIMES
5260 {
5261 /* Not sure if this can happen */
5262 PyErr_SetString(
5263 PyExc_RuntimeError,
5264 "neither futimens nor futimes are supported"
5265 " on this system");
5266 return -1;
5267 }
5268 #endif
5269
5270 #endif
5271 #ifdef HAVE_FUTIMES
5272 {
5273 UTIME_TO_TIMEVAL;
5274 return futimes(fd, time);
5275 }
5276 #endif
5277 }
5278
5279 #define PATH_UTIME_HAVE_FD 1
5280 #else
5281 #define PATH_UTIME_HAVE_FD 0
5282 #endif
5283
5284 #if defined(HAVE_UTIMENSAT) || defined(HAVE_LUTIMES)
5285 # define UTIME_HAVE_NOFOLLOW_SYMLINKS
5286 #endif
5287
5288 #ifdef UTIME_HAVE_NOFOLLOW_SYMLINKS
5289
5290 static int
5291 utime_nofollow_symlinks(utime_t *ut, const char *path)
5292 {
5293 #ifdef HAVE_UTIMENSAT
5294 if (HAVE_UTIMENSAT_RUNTIME) {
5295 UTIME_TO_TIMESPEC;
5296 return utimensat(DEFAULT_DIR_FD, path, time, AT_SYMLINK_NOFOLLOW);
5297 } else
5298 #ifndef HAVE_LUTIMES
5299 {
5300 /* Not sure if this can happen */
5301 PyErr_SetString(
5302 PyExc_RuntimeError,
5303 "neither utimensat nor lutimes are supported"
5304 " on this system");
5305 return -1;
5306 }
5307 #endif
5308 #endif
5309
5310 #ifdef HAVE_LUTIMES
5311 {
5312 UTIME_TO_TIMEVAL;
5313 return lutimes(path, time);
5314 }
5315 #endif
5316 }
5317
5318 #endif
5319
5320 #ifndef MS_WINDOWS
5321
5322 static int
5323 3426 utime_default(utime_t *ut, const char *path)
5324 {
5325 #if defined(__APPLE__) && defined(HAVE_UTIMENSAT)
5326 if (HAVE_UTIMENSAT_RUNTIME) {
5327 UTIME_TO_TIMESPEC;
5328 return utimensat(DEFAULT_DIR_FD, path, time, 0);
5329 } else {
5330 UTIME_TO_TIMEVAL;
5331 return utimes(path, time);
5332 }
5333 #elif defined(HAVE_UTIMENSAT)
5334
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 3410 times.
3426 UTIME_TO_TIMESPEC;
5335 3426 return utimensat(DEFAULT_DIR_FD, path, time, 0);
5336 #elif defined(HAVE_UTIMES)
5337 UTIME_TO_TIMEVAL;
5338 return utimes(path, time);
5339 #elif defined(HAVE_UTIME_H)
5340 UTIME_TO_UTIMBUF;
5341 return utime(path, time);
5342 #else
5343 UTIME_TO_TIME_T;
5344 return utime(path, time);
5345 #endif
5346 }
5347
5348 #endif
5349
5350 static int
5351 134 split_py_long_to_s_and_ns(PyObject *module, PyObject *py_long, time_t *s, long *ns)
5352 {
5353 134 int result = 0;
5354 PyObject *divmod;
5355 134 divmod = PyNumber_Divmod(py_long, get_posix_state(module)->billion);
5356
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 134 times.
134 if (!divmod)
5357 goto exit;
5358
2/4
✓ Branch 2 taken 134 times.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 134 times.
134 if (!PyTuple_Check(divmod) || PyTuple_GET_SIZE(divmod) != 2) {
5359 PyErr_Format(PyExc_TypeError,
5360 "%.200s.__divmod__() must return a 2-tuple, not %.200s",
5361 _PyType_Name(Py_TYPE(py_long)), _PyType_Name(Py_TYPE(divmod)));
5362 goto exit;
5363 }
5364 134 *s = _PyLong_AsTime_t(PyTuple_GET_ITEM(divmod, 0));
5365
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 134 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
134 if ((*s == -1) && PyErr_Occurred())
5366 goto exit;
5367 134 *ns = PyLong_AsLong(PyTuple_GET_ITEM(divmod, 1));
5368
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 134 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
134 if ((*ns == -1) && PyErr_Occurred())
5369 goto exit;
5370
5371 134 result = 1;
5372 134 exit:
5373 134 Py_XDECREF(divmod);
5374 134 return result;
5375 }
5376
5377
5378 /*[clinic input]
5379 os.utime
5380
5381 path: path_t(allow_fd='PATH_UTIME_HAVE_FD')
5382 times: object = None
5383 *
5384 ns: object = NULL
5385 dir_fd: dir_fd(requires='futimensat') = None
5386 follow_symlinks: bool=True
5387
5388 # "utime(path, times=None, *[, ns], dir_fd=None, follow_symlinks=True)\n\
5389
5390 Set the access and modified time of path.
5391
5392 path may always be specified as a string.
5393 On some platforms, path may also be specified as an open file descriptor.
5394 If this functionality is unavailable, using it raises an exception.
5395
5396 If times is not None, it must be a tuple (atime, mtime);
5397 atime and mtime should be expressed as float seconds since the epoch.
5398 If ns is specified, it must be a tuple (atime_ns, mtime_ns);
5399 atime_ns and mtime_ns should be expressed as integer nanoseconds
5400 since the epoch.
5401 If times is None and ns is unspecified, utime uses the current time.
5402 Specifying tuples for both times and ns is an error.
5403
5404 If dir_fd is not None, it should be a file descriptor open to a directory,
5405 and path should be relative; path will then be relative to that directory.
5406 If follow_symlinks is False, and the last element of the path is a symbolic
5407 link, utime will modify the symbolic link itself instead of the file the
5408 link points to.
5409 It is an error to use dir_fd or follow_symlinks when specifying path
5410 as an open file descriptor.
5411 dir_fd and follow_symlinks may not be available on your platform.
5412 If they are unavailable, using them will raise a NotImplementedError.
5413
5414 [clinic start generated code]*/
5415
5416 static PyObject *
5417 3426 os_utime_impl(PyObject *module, path_t *path, PyObject *times, PyObject *ns,
5418 int dir_fd, int follow_symlinks)
5419 /*[clinic end generated code: output=cfcac69d027b82cf input=2fbd62a2f228f8f4]*/
5420 {
5421 #ifdef MS_WINDOWS
5422 HANDLE hFile;
5423 FILETIME atime, mtime;
5424 #else
5425 int result;
5426 #endif
5427
5428 utime_t utime;
5429
5430 3426 memset(&utime, 0, sizeof(utime_t));
5431
5432
3/4
✓ Branch 0 taken 3343 times.
✓ Branch 1 taken 83 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3343 times.
3426 if (times != Py_None && ns) {
5433 PyErr_SetString(PyExc_ValueError,
5434 "utime: you may specify either 'times'"
5435 " or 'ns' but not both");
5436 return NULL;
5437 }
5438
5439
2/2
✓ Branch 0 taken 3343 times.
✓ Branch 1 taken 83 times.
3426 if (times != Py_None) {
5440 time_t a_sec, m_sec;
5441 long a_nsec, m_nsec;
5442
2/4
✓ Branch 1 taken 3343 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3343 times.
3343 if (!PyTuple_CheckExact(times) || (PyTuple_Size(times) != 2)) {
5443 PyErr_SetString(PyExc_TypeError,
5444 "utime: 'times' must be either"
5445 " a tuple of two ints or None");
5446 return NULL;
5447 }
5448 3343 utime.now = 0;
5449
1/2
✓ Branch 1 taken 3343 times.
✗ Branch 2 not taken.
3343 if (_PyTime_ObjectToTimespec(PyTuple_GET_ITEM(times, 0),
5450
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3343 times.
3343 &a_sec, &a_nsec, _PyTime_ROUND_FLOOR) == -1 ||
5451 3343 _PyTime_ObjectToTimespec(PyTuple_GET_ITEM(times, 1),
5452 &m_sec, &m_nsec, _PyTime_ROUND_FLOOR) == -1) {
5453 return NULL;
5454 }
5455 3343 utime.atime_s = a_sec;
5456 3343 utime.atime_ns = a_nsec;
5457 3343 utime.mtime_s = m_sec;
5458 3343 utime.mtime_ns = m_nsec;
5459 }
5460
2/2
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 16 times.
83 else if (ns) {
5461
2/4
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 67 times.
67 if (!PyTuple_CheckExact(ns) || (PyTuple_Size(ns) != 2)) {
5462 PyErr_SetString(PyExc_TypeError,
5463 "utime: 'ns' must be a tuple of two ints");
5464 return NULL;
5465 }
5466 67 utime.now = 0;
5467
1/2
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
67 if (!split_py_long_to_s_and_ns(module, PyTuple_GET_ITEM(ns, 0),
5468
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 67 times.
67 &utime.atime_s, &utime.atime_ns) ||
5469 67 !split_py_long_to_s_and_ns(module, PyTuple_GET_ITEM(ns, 1),
5470 &utime.mtime_s, &utime.mtime_ns)) {
5471 return NULL;
5472 }
5473 }
5474 else {
5475 /* times and ns are both None/unspecified. use "now". */
5476 16 utime.now = 1;
5477 }
5478
5479 #if !defined(UTIME_HAVE_NOFOLLOW_SYMLINKS)
5480 if (follow_symlinks_specified("utime", follow_symlinks))
5481 return NULL;
5482 #endif
5483
5484
2/4
✓ Branch 1 taken 3426 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3426 times.
✗ Branch 4 not taken.
6852 if (path_and_dir_fd_invalid("utime", path, dir_fd) ||
5485
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3426 times.
6852 dir_fd_and_fd_invalid("utime", dir_fd, path->fd) ||
5486 3426 fd_and_follow_symlinks_invalid("utime", path->fd, follow_symlinks))
5487 return NULL;
5488
5489 #if !defined(HAVE_UTIMENSAT)
5490 if ((dir_fd != DEFAULT_DIR_FD) && (!follow_symlinks)) {
5491 PyErr_SetString(PyExc_ValueError,
5492 "utime: cannot use dir_fd and follow_symlinks "
5493 "together on this platform");
5494 return NULL;
5495 }
5496 #endif
5497
5498
4/6
✗ Branch 0 not taken.
✓ Branch 1 taken 3426 times.
✓ Branch 2 taken 67 times.
✓ Branch 3 taken 3359 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3426 times.
3426 if (PySys_Audit("os.utime", "OOOi", path->object, times, ns ? ns : Py_None,
5499 dir_fd == DEFAULT_DIR_FD ? -1 : dir_fd) < 0) {
5500 return NULL;
5501 }
5502
5503 #ifdef MS_WINDOWS
5504 Py_BEGIN_ALLOW_THREADS
5505 hFile = CreateFileW(path->wide, FILE_WRITE_ATTRIBUTES, 0,
5506 NULL, OPEN_EXISTING,
5507 FILE_FLAG_BACKUP_SEMANTICS, NULL);
5508 Py_END_ALLOW_THREADS
5509 if (hFile == INVALID_HANDLE_VALUE) {
5510 path_error(path);
5511 return NULL;
5512 }
5513
5514 if (utime.now) {
5515 GetSystemTimeAsFileTime(&mtime);
5516 atime = mtime;
5517 }
5518 else {
5519 _Py_time_t_to_FILE_TIME(utime.atime_s, utime.atime_ns, &atime);
5520 _Py_time_t_to_FILE_TIME(utime.mtime_s, utime.mtime_ns, &mtime);
5521 }
5522 if (!SetFileTime(hFile, NULL, &atime, &mtime)) {
5523 /* Avoid putting the file name into the error here,
5524 as that may confuse the user into believing that
5525 something is wrong with the file, when it also
5526 could be the time stamp that gives a problem. */
5527 PyErr_SetFromWindowsErr(0);
5528 CloseHandle(hFile);
5529 return NULL;
5530 }
5531 CloseHandle(hFile);
5532 #else /* MS_WINDOWS */
5533 3426 Py_BEGIN_ALLOW_THREADS
5534
5535 #ifdef UTIME_HAVE_NOFOLLOW_SYMLINKS
5536
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3426 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
3426 if ((!follow_symlinks) && (dir_fd == DEFAULT_DIR_FD))
5537 result = utime_nofollow_symlinks(&utime, path->narrow);
5538 else
5539 #endif
5540
5541 #if defined(HAVE_FUTIMESAT) || defined(HAVE_UTIMENSAT)
5542
2/4
✓ Branch 0 taken 3426 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3426 times.
3426 if ((dir_fd != DEFAULT_DIR_FD) || (!follow_symlinks)) {
5543 result = utime_dir_fd(&utime, dir_fd, path->narrow, follow_symlinks);
5544
5545 } else
5546 #endif
5547
5548 #if defined(HAVE_FUTIMES) || defined(HAVE_FUTIMENS)
5549
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3426 times.
3426 if (path->fd != -1)
5550 result = utime_fd(&utime, path->fd);
5551 else
5552 #endif
5553
5554 3426 result = utime_default(&utime, path->narrow);
5555
5556 3426 Py_END_ALLOW_THREADS
5557
5558 #if defined(__APPLE__) && defined(HAVE_UTIMENSAT)
5559 /* See utime_dir_fd implementation */
5560 if (result == -1 && errno == ENOSYS) {
5561 argument_unavailable_error(NULL, "dir_fd");
5562 return NULL;
5563 }
5564 #endif
5565
5566
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3426 times.
3426 if (result < 0) {
5567 /* see previous comment about not putting filename in error here */
5568 posix_error();
5569 return NULL;
5570 }
5571
5572 #endif /* MS_WINDOWS */
5573
5574 3426 Py_RETURN_NONE;
5575 }
5576
5577 /* Process operations */
5578
5579
5580 /*[clinic input]
5581 os._exit
5582
5583 status: int
5584
5585 Exit to the system with specified status, without normal exit processing.
5586 [clinic start generated code]*/
5587
5588 static PyObject *
5589 os__exit_impl(PyObject *module, int status)
5590 /*[clinic end generated code: output=116e52d9c2260d54 input=5e6d57556b0c4a62]*/
5591 {
5592 _exit(status);
5593 return NULL; /* Make gcc -Wall happy */
5594 }
5595
5596 #if defined(HAVE_WEXECV) || defined(HAVE_WSPAWNV)
5597 #define EXECV_CHAR wchar_t
5598 #else
5599 #define EXECV_CHAR char
5600 #endif
5601
5602 #if defined(HAVE_EXECV) || defined(HAVE_SPAWNV) || defined(HAVE_RTPSPAWN)
5603 static void
5604 free_string_array(EXECV_CHAR **array, Py_ssize_t count)
5605 {
5606 Py_ssize_t i;
5607 for (i = 0; i < count; i++)
5608 PyMem_Free(array[i]);
5609 PyMem_Free(array);
5610 }
5611
5612 static int
5613 fsconvert_strdup(PyObject *o, EXECV_CHAR **out)
5614 {
5615 Py_ssize_t size;
5616 PyObject *ub;
5617 int result = 0;
5618 #if defined(HAVE_WEXECV) || defined(HAVE_WSPAWNV)
5619 if (!PyUnicode_FSDecoder(o, &ub))
5620 return 0;
5621 *out = PyUnicode_AsWideCharString(ub, &size);
5622 if (*out)
5623 result = 1;
5624 #else
5625 if (!PyUnicode_FSConverter(o, &ub))
5626 return 0;
5627 size = PyBytes_GET_SIZE(ub);
5628 *out = PyMem_Malloc(size + 1);
5629 if (*out) {
5630 memcpy(*out, PyBytes_AS_STRING(ub), size + 1);
5631 result = 1;
5632 } else
5633 PyErr_NoMemory();
5634 #endif
5635 Py_DECREF(ub);
5636 return result;
5637 }
5638 #endif
5639
5640 #if defined(HAVE_EXECV) || defined (HAVE_FEXECVE) || defined(HAVE_RTPSPAWN)
5641 static EXECV_CHAR**
5642 parse_envlist(PyObject* env, Py_ssize_t *envc_ptr)
5643 {
5644 Py_ssize_t i, pos, envc;
5645 PyObject *keys=NULL, *vals=NULL;
5646 PyObject *key, *val, *key2, *val2, *keyval;
5647 EXECV_CHAR **envlist;
5648
5649 i = PyMapping_Size(env);
5650 if (i < 0)
5651 return NULL;
5652 envlist = PyMem_NEW(EXECV_CHAR *, i + 1);
5653 if (envlist == NULL) {
5654 PyErr_NoMemory();
5655 return NULL;
5656 }
5657 envc = 0;
5658 keys = PyMapping_Keys(env);
5659 if (!keys)
5660 goto error;
5661 vals = PyMapping_Values(env);
5662 if (!vals)
5663 goto error;
5664 if (!PyList_Check(keys) || !PyList_Check(vals)) {
5665 PyErr_Format(PyExc_TypeError,
5666 "env.keys() or env.values() is not a list");
5667 goto error;
5668 }
5669
5670 for (pos = 0; pos < i; pos++) {
5671 key = PyList_GetItem(keys, pos);
5672 val = PyList_GetItem(vals, pos);
5673 if (!key || !val)
5674 goto error;
5675
5676 #if defined(HAVE_WEXECV) || defined(HAVE_WSPAWNV)
5677 if (!PyUnicode_FSDecoder(key, &key2))
5678 goto error;
5679 if (!PyUnicode_FSDecoder(val, &val2)) {
5680 Py_DECREF(key2);
5681 goto error;
5682 }
5683 /* Search from index 1 because on Windows starting '=' is allowed for
5684 defining hidden environment variables. */
5685 if (PyUnicode_GET_LENGTH(key2) == 0 ||
5686 PyUnicode_FindChar(key2, '=', 1, PyUnicode_GET_LENGTH(key2), 1) != -1)
5687 {
5688 PyErr_SetString(PyExc_ValueError, "illegal environment variable name");
5689 Py_DECREF(key2);
5690 Py_DECREF(val2);
5691 goto error;
5692 }
5693 keyval = PyUnicode_FromFormat("%U=%U", key2, val2);
5694 #else
5695 if (!PyUnicode_FSConverter(key, &key2))
5696 goto error;
5697 if (!PyUnicode_FSConverter(val, &val2)) {
5698 Py_DECREF(key2);
5699 goto error;
5700 }
5701 if (PyBytes_GET_SIZE(key2) == 0 ||
5702 strchr(PyBytes_AS_STRING(key2) + 1, '=') != NULL)
5703 {
5704 PyErr_SetString(PyExc_ValueError, "illegal environment variable name");
5705 Py_DECREF(key2);
5706 Py_DECREF(val2);
5707 goto error;
5708 }
5709 keyval = PyBytes_FromFormat("%s=%s", PyBytes_AS_STRING(key2),
5710 PyBytes_AS_STRING(val2));
5711 #endif
5712 Py_DECREF(key2);
5713 Py_DECREF(val2);
5714 if (!keyval)
5715 goto error;
5716
5717 if (!fsconvert_strdup(keyval, &envlist[envc++])) {
5718 Py_DECREF(keyval);
5719 goto error;
5720 }
5721
5722 Py_DECREF(keyval);
5723 }
5724 Py_DECREF(vals);
5725 Py_DECREF(keys);
5726
5727 envlist[envc] = 0;
5728 *envc_ptr = envc;
5729 return envlist;
5730
5731 error:
5732 Py_XDECREF(keys);
5733 Py_XDECREF(vals);
5734 free_string_array(envlist, envc);
5735 return NULL;
5736 }
5737
5738 static EXECV_CHAR**
5739 parse_arglist(PyObject* argv, Py_ssize_t *argc)
5740 {
5741 int i;
5742 EXECV_CHAR **argvlist = PyMem_NEW(EXECV_CHAR *, *argc+1);
5743 if (argvlist == NULL) {
5744 PyErr_NoMemory();
5745 return NULL;
5746 }
5747 for (i = 0; i < *argc; i++) {
5748 PyObject* item = PySequence_ITEM(argv, i);
5749 if (item == NULL)
5750 goto fail;
5751 if (!fsconvert_strdup(item, &argvlist[i])) {
5752 Py_DECREF(item);
5753 goto fail;
5754 }
5755 Py_DECREF(item);
5756 }
5757 argvlist[*argc] = NULL;
5758 return argvlist;
5759 fail:
5760 *argc = i;
5761 free_string_array(argvlist, *argc);
5762 return NULL;
5763 }
5764
5765 #endif
5766
5767
5768 #ifdef HAVE_EXECV
5769 /*[clinic input]
5770 os.execv
5771
5772 path: path_t
5773 Path of executable file.
5774 argv: object
5775 Tuple or list of strings.
5776 /
5777
5778 Execute an executable path with arguments, replacing current process.
5779 [clinic start generated code]*/
5780
5781 static PyObject *
5782 os_execv_impl(PyObject *module, path_t *path, PyObject *argv)
5783 /*[clinic end generated code: output=3b52fec34cd0dafd input=9bac31efae07dac7]*/
5784 {
5785 EXECV_CHAR **argvlist;
5786 Py_ssize_t argc;
5787
5788 /* execv has two arguments: (path, argv), where
5789 argv is a list or tuple of strings. */
5790
5791 if (!PyList_Check(argv) && !PyTuple_Check(argv)) {
5792 PyErr_SetString(PyExc_TypeError,
5793 "execv() arg 2 must be a tuple or list");
5794 return NULL;
5795 }
5796 argc = PySequence_Size(argv);
5797 if (argc < 1) {
5798 PyErr_SetString(PyExc_ValueError, "execv() arg 2 must not be empty");
5799 return NULL;
5800 }
5801
5802 argvlist = parse_arglist(argv, &argc);
5803 if (argvlist == NULL) {
5804 return NULL;
5805 }
5806 if (!argvlist[0][0]) {
5807 PyErr_SetString(PyExc_ValueError,
5808 "execv() arg 2 first element cannot be empty");
5809 free_string_array(argvlist, argc);
5810 return NULL;
5811 }
5812
5813 if (PySys_Audit("os.exec", "OOO", path->object, argv, Py_None) < 0) {
5814 free_string_array(argvlist, argc);
5815 return NULL;
5816 }
5817
5818 _Py_BEGIN_SUPPRESS_IPH
5819 #ifdef HAVE_WEXECV
5820 _wexecv(path->wide, argvlist);
5821 #else
5822 execv(path->narrow, argvlist);
5823 #endif
5824 _Py_END_SUPPRESS_IPH
5825
5826 /* If we get here it's definitely an error */
5827
5828 free_string_array(argvlist, argc);
5829 return posix_error();
5830 }
5831
5832
5833 /*[clinic input]
5834 os.execve
5835
5836 path: path_t(allow_fd='PATH_HAVE_FEXECVE')
5837 Path of executable file.
5838 argv: object
5839 Tuple or list of strings.
5840 env: object
5841 Dictionary of strings mapping to strings.
5842
5843 Execute an executable path with arguments, replacing current process.
5844 [clinic start generated code]*/
5845
5846 static PyObject *
5847 os_execve_impl(PyObject *module, path_t *path, PyObject *argv, PyObject *env)
5848 /*[clinic end generated code: output=ff9fa8e4da8bde58 input=626804fa092606d9]*/
5849 {
5850 EXECV_CHAR **argvlist = NULL;
5851 EXECV_CHAR **envlist;
5852 Py_ssize_t argc, envc;
5853
5854 /* execve has three arguments: (path, argv, env), where
5855 argv is a list or tuple of strings and env is a dictionary
5856 like posix.environ. */
5857
5858 if (!PyList_Check(argv) && !PyTuple_Check(argv)) {
5859 PyErr_SetString(PyExc_TypeError,
5860 "execve: argv must be a tuple or list");
5861 goto fail_0;
5862 }
5863 argc = PySequence_Size(argv);
5864 if (argc < 1) {
5865 PyErr_SetString(PyExc_ValueError, "execve: argv must not be empty");
5866 return NULL;
5867 }
5868
5869 if (!PyMapping_Check(env)) {
5870 PyErr_SetString(PyExc_TypeError,
5871 "execve: environment must be a mapping object");
5872 goto fail_0;
5873 }
5874
5875 argvlist = parse_arglist(argv, &argc);
5876 if (argvlist == NULL) {
5877 goto fail_0;
5878 }
5879 if (!argvlist[0][0]) {
5880 PyErr_SetString(PyExc_ValueError,
5881 "execve: argv first element cannot be empty");
5882 goto fail_0;
5883 }
5884
5885 envlist = parse_envlist(env, &envc);
5886 if (envlist == NULL)
5887 goto fail_0;
5888
5889 if (PySys_Audit("os.exec", "OOO", path->object, argv, env) < 0) {
5890 goto fail_1;
5891 }
5892
5893 _Py_BEGIN_SUPPRESS_IPH
5894 #ifdef HAVE_FEXECVE
5895 if (path->fd > -1)
5896 fexecve(path->fd, argvlist, envlist);
5897 else
5898 #endif
5899 #ifdef HAVE_WEXECV
5900 _wexecve(path->wide, argvlist, envlist);
5901 #else
5902 execve(path->narrow, argvlist, envlist);
5903 #endif
5904 _Py_END_SUPPRESS_IPH
5905
5906 /* If we get here it's definitely an error */
5907
5908 posix_path_error(path);
5909 fail_1:
5910 free_string_array(envlist, envc);
5911 fail_0:
5912 if (argvlist)
5913 free_string_array(argvlist, argc);
5914 return NULL;
5915 }
5916
5917 #endif /* HAVE_EXECV */
5918
5919 #ifdef HAVE_POSIX_SPAWN
5920
5921 enum posix_spawn_file_actions_identifier {
5922 POSIX_SPAWN_OPEN,
5923 POSIX_SPAWN_CLOSE,
5924 POSIX_SPAWN_DUP2
5925 };
5926
5927 #if defined(HAVE_SCHED_SETPARAM) || defined(HAVE_SCHED_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDPARAM)
5928 static int
5929 convert_sched_param(PyObject *module, PyObject *param, struct sched_param *res);
5930 #endif
5931
5932 static int
5933 parse_posix_spawn_flags(PyObject *module, const char *func_name, PyObject *setpgroup,
5934 int resetids, int setsid, PyObject *setsigmask,
5935 PyObject *setsigdef, PyObject *scheduler,
5936 posix_spawnattr_t *attrp)
5937 {
5938 long all_flags = 0;
5939
5940 errno = posix_spawnattr_init(attrp);
5941 if (errno) {
5942 posix_error();
5943 return -1;
5944 }
5945
5946 if (setpgroup) {
5947 pid_t pgid = PyLong_AsPid(setpgroup);
5948 if (pgid == (pid_t)-1 && PyErr_Occurred()) {
5949 goto fail;
5950 }
5951 errno = posix_spawnattr_setpgroup(attrp, pgid);
5952 if (errno) {
5953 posix_error();
5954 goto fail;
5955 }
5956 all_flags |= POSIX_SPAWN_SETPGROUP;
5957 }
5958
5959 if (resetids) {
5960 all_flags |= POSIX_SPAWN_RESETIDS;
5961 }
5962
5963 if (setsid) {
5964 #ifdef HAVE_POSIX_SPAWN_SETSID_RUNTIME
5965 if (HAVE_POSIX_SPAWN_SETSID_RUNTIME) {
5966 #endif
5967 #ifdef POSIX_SPAWN_SETSID
5968 all_flags |= POSIX_SPAWN_SETSID;
5969 #elif defined(POSIX_SPAWN_SETSID_NP)
5970 all_flags |= POSIX_SPAWN_SETSID_NP;
5971 #else
5972 argument_unavailable_error(func_name, "setsid");
5973 return -1;
5974 #endif
5975
5976 #ifdef HAVE_POSIX_SPAWN_SETSID_RUNTIME
5977 } else {
5978 argument_unavailable_error(func_name, "setsid");
5979 return -1;
5980 }
5981 #endif /* HAVE_POSIX_SPAWN_SETSID_RUNTIME */
5982
5983 }
5984
5985 #ifdef HAVE_SIGSET_T
5986 if (setsigmask) {
5987 sigset_t set;
5988 if (!_Py_Sigset_Converter(setsigmask, &set)) {
5989 goto fail;
5990 }
5991 errno = posix_spawnattr_setsigmask(attrp, &set);
5992 if (errno) {
5993 posix_error();
5994 goto fail;
5995 }
5996 all_flags |= POSIX_SPAWN_SETSIGMASK;
5997 }
5998
5999 if (setsigdef) {
6000 sigset_t set;
6001 if (!_Py_Sigset_Converter(setsigdef, &set)) {
6002 goto fail;
6003 }
6004 errno = posix_spawnattr_setsigdefault(attrp, &set);
6005 if (errno) {
6006 posix_error();
6007 goto fail;
6008 }
6009 all_flags |= POSIX_SPAWN_SETSIGDEF;
6010 }
6011 #else
6012 if (setsigmask || setsigdef) {
6013 PyErr_SetString(PyExc_NotImplementedError,
6014 "sigset is not supported on this platform");
6015 goto fail;
6016 }
6017 #endif
6018
6019 if (scheduler) {
6020 #ifdef POSIX_SPAWN_SETSCHEDULER
6021 PyObject *py_schedpolicy;
6022 PyObject *schedparam_obj;
6023 struct sched_param schedparam;
6024
6025 if (!PyArg_ParseTuple(scheduler, "OO"
6026 ";A scheduler tuple must have two elements",
6027 &py_schedpolicy, &schedparam_obj)) {
6028 goto fail;
6029 }
6030 if (!convert_sched_param(module, schedparam_obj, &schedparam)) {
6031 goto fail;
6032 }
6033 if (py_schedpolicy != Py_None) {
6034 int schedpolicy = _PyLong_AsInt(py_schedpolicy);
6035
6036 if (schedpolicy == -1 && PyErr_Occurred()) {
6037 goto fail;
6038 }
6039 errno = posix_spawnattr_setschedpolicy(attrp, schedpolicy);
6040 if (errno) {
6041 posix_error();
6042 goto fail;
6043 }
6044 all_flags |= POSIX_SPAWN_SETSCHEDULER;
6045 }
6046 errno = posix_spawnattr_setschedparam(attrp, &schedparam);
6047 if (errno) {
6048 posix_error();
6049 goto fail;
6050 }
6051 all_flags |= POSIX_SPAWN_SETSCHEDPARAM;
6052 #else
6053 PyErr_SetString(PyExc_NotImplementedError,
6054 "The scheduler option is not supported in this system.");
6055 goto fail;
6056 #endif
6057 }
6058
6059 errno = posix_spawnattr_setflags(attrp, all_flags);
6060 if (errno) {
6061 posix_error();
6062 goto fail;
6063 }
6064
6065 return 0;
6066
6067 fail:
6068 (void)posix_spawnattr_destroy(attrp);
6069 return -1;
6070 }
6071
6072 static int
6073 parse_file_actions(PyObject *file_actions,
6074 posix_spawn_file_actions_t *file_actionsp,
6075 PyObject *temp_buffer)
6076 {
6077 PyObject *seq;
6078 PyObject *file_action = NULL;
6079 PyObject *tag_obj;
6080
6081 seq = PySequence_Fast(file_actions,
6082 "file_actions must be a sequence or None");
6083 if (seq == NULL) {
6084 return -1;
6085 }
6086
6087 errno = posix_spawn_file_actions_init(file_actionsp);
6088 if (errno) {
6089 posix_error();
6090 Py_DECREF(seq);
6091 return -1;
6092 }
6093
6094 for (Py_ssize_t i = 0; i < PySequence_Fast_GET_SIZE(seq); ++i) {
6095 file_action = PySequence_Fast_GET_ITEM(seq, i);
6096 Py_INCREF(file_action);
6097 if (!PyTuple_Check(file_action) || !PyTuple_GET_SIZE(file_action)) {
6098 PyErr_SetString(PyExc_TypeError,
6099 "Each file_actions element must be a non-empty tuple");
6100 goto fail;
6101 }
6102 long tag = PyLong_AsLong(PyTuple_GET_ITEM(file_action, 0));
6103 if (tag == -1 && PyErr_Occurred()) {
6104 goto fail;
6105 }
6106
6107 /* Populate the file_actions object */
6108 switch (tag) {
6109 case POSIX_SPAWN_OPEN: {
6110 int fd, oflag;
6111 PyObject *path;
6112 unsigned long mode;
6113 if (!PyArg_ParseTuple(file_action, "OiO&ik"
6114 ";A open file_action tuple must have 5 elements",
6115 &tag_obj, &fd, PyUnicode_FSConverter, &path,
6116 &oflag, &mode))
6117 {
6118 goto fail;
6119 }
6120 if (PyList_Append(temp_buffer, path)) {
6121 Py_DECREF(path);
6122 goto fail;
6123 }
6124 errno = posix_spawn_file_actions_addopen(file_actionsp,
6125 fd, PyBytes_AS_STRING(path), oflag, (mode_t)mode);
6126 Py_DECREF(path);
6127 if (errno) {
6128 posix_error();
6129 goto fail;
6130 }
6131 break;
6132 }
6133 case POSIX_SPAWN_CLOSE: {
6134 int fd;
6135 if (!PyArg_ParseTuple(file_action, "Oi"
6136 ";A close file_action tuple must have 2 elements",
6137 &tag_obj, &fd))
6138 {
6139 goto fail;
6140 }
6141 errno = posix_spawn_file_actions_addclose(file_actionsp, fd);
6142 if (errno) {
6143 posix_error();
6144 goto fail;
6145 }
6146 break;
6147 }
6148 case POSIX_SPAWN_DUP2: {
6149 int fd1, fd2;
6150 if (!PyArg_ParseTuple(file_action, "Oii"
6151 ";A dup2 file_action tuple must have 3 elements",
6152 &tag_obj, &fd1, &fd2))
6153 {
6154 goto fail;
6155 }
6156 errno = posix_spawn_file_actions_adddup2(file_actionsp,
6157 fd1, fd2);
6158 if (errno) {
6159 posix_error();
6160 goto fail;
6161 }
6162 break;
6163 }
6164 default: {
6165 PyErr_SetString(PyExc_TypeError,
6166 "Unknown file_actions identifier");
6167 goto fail;
6168 }
6169 }
6170 Py_DECREF(file_action);
6171 }
6172
6173 Py_DECREF(seq);
6174 return 0;
6175
6176 fail:
6177 Py_DECREF(seq);
6178 Py_DECREF(file_action);
6179 (void)posix_spawn_file_actions_destroy(file_actionsp);
6180 return -1;
6181 }
6182
6183
6184 static PyObject *
6185 py_posix_spawn(int use_posix_spawnp, PyObject *module, path_t *path, PyObject *argv,
6186 PyObject *env, PyObject *file_actions,
6187 PyObject *setpgroup, int resetids, int setsid, PyObject *setsigmask,
6188 PyObject *setsigdef, PyObject *scheduler)
6189 {
6190 const char *func_name = use_posix_spawnp ? "posix_spawnp" : "posix_spawn";
6191 EXECV_CHAR **argvlist = NULL;
6192 EXECV_CHAR **envlist = NULL;
6193 posix_spawn_file_actions_t file_actions_buf;
6194 posix_spawn_file_actions_t *file_actionsp = NULL;
6195 posix_spawnattr_t attr;
6196 posix_spawnattr_t *attrp = NULL;
6197 Py_ssize_t argc, envc;
6198 PyObject *result = NULL;
6199 PyObject *temp_buffer = NULL;
6200 pid_t pid;
6201 int err_code;
6202
6203 /* posix_spawn and posix_spawnp have three arguments: (path, argv, env), where
6204 argv is a list or tuple of strings and env is a dictionary
6205 like posix.environ. */
6206
6207 if (!PyList_Check(argv) && !PyTuple_Check(argv)) {
6208 PyErr_Format(PyExc_TypeError,
6209 "%s: argv must be a tuple or list", func_name);
6210 goto exit;
6211 }
6212 argc = PySequence_Size(argv);
6213 if (argc < 1) {
6214 PyErr_Format(PyExc_ValueError,
6215 "%s: argv must not be empty", func_name);
6216 return NULL;
6217 }
6218
6219 if (!PyMapping_Check(env)) {
6220 PyErr_Format(PyExc_TypeError,
6221 "%s: environment must be a mapping object", func_name);
6222 goto exit;
6223 }
6224
6225 argvlist = parse_arglist(argv, &argc);
6226 if (argvlist == NULL) {
6227 goto exit;
6228 }
6229 if (!argvlist[0][0]) {
6230 PyErr_Format(PyExc_ValueError,
6231 "%s: argv first element cannot be empty", func_name);
6232 goto exit;
6233 }
6234
6235 envlist = parse_envlist(env, &envc);
6236 if (envlist == NULL) {
6237 goto exit;
6238 }
6239
6240 if (file_actions != NULL && file_actions != Py_None) {
6241 /* There is a bug in old versions of glibc that makes some of the
6242 * helper functions for manipulating file actions not copy the provided
6243 * buffers. The problem is that posix_spawn_file_actions_addopen does not
6244 * copy the value of path for some old versions of glibc (<2.20).
6245 * The use of temp_buffer here is a workaround that keeps the
6246 * python objects that own the buffers alive until posix_spawn gets called.
6247 * Check https://bugs.python.org/issue33630 and
6248 * https://sourceware.org/bugzilla/show_bug.cgi?id=17048 for more info.*/
6249 temp_buffer = PyList_New(0);
6250 if (!temp_buffer) {
6251 goto exit;
6252 }
6253 if (parse_file_actions(file_actions, &file_actions_buf, temp_buffer)) {
6254 goto exit;
6255 }
6256 file_actionsp = &file_actions_buf;
6257 }
6258
6259 if (parse_posix_spawn_flags(module, func_name, setpgroup, resetids, setsid,
6260 setsigmask, setsigdef, scheduler, &attr)) {
6261 goto exit;
6262 }
6263 attrp = &attr;
6264
6265 if (PySys_Audit("os.posix_spawn", "OOO", path->object, argv, env) < 0) {
6266 goto exit;
6267 }
6268
6269 _Py_BEGIN_SUPPRESS_IPH
6270 #ifdef HAVE_POSIX_SPAWNP
6271 if (use_posix_spawnp) {
6272 err_code = posix_spawnp(&pid, path->narrow,
6273 file_actionsp, attrp, argvlist, envlist);
6274 }
6275 else
6276 #endif /* HAVE_POSIX_SPAWNP */
6277 {
6278 err_code = posix_spawn(&pid, path->narrow,
6279 file_actionsp, attrp, argvlist, envlist);
6280 }
6281 _Py_END_SUPPRESS_IPH
6282
6283 if (err_code) {
6284 errno = err_code;
6285 PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path->object);
6286 goto exit;
6287 }
6288 #ifdef _Py_MEMORY_SANITIZER
6289 __msan_unpoison(&pid, sizeof(pid));
6290 #endif
6291 result = PyLong_FromPid(pid);
6292
6293 exit:
6294 if (file_actionsp) {
6295 (void)posix_spawn_file_actions_destroy(file_actionsp);
6296 }
6297 if (attrp) {
6298 (void)posix_spawnattr_destroy(attrp);
6299 }
6300 if (envlist) {
6301 free_string_array(envlist, envc);
6302 }
6303 if (argvlist) {
6304 free_string_array(argvlist, argc);
6305 }
6306 Py_XDECREF(temp_buffer);
6307 return result;
6308 }
6309
6310
6311 /*[clinic input]
6312
6313 os.posix_spawn
6314 path: path_t
6315 Path of executable file.
6316 argv: object
6317 Tuple or list of strings.
6318 env: object
6319 Dictionary of strings mapping to strings.
6320 /
6321 *
6322 file_actions: object(c_default='NULL') = ()
6323 A sequence of file action tuples.
6324 setpgroup: object = NULL
6325 The pgroup to use with the POSIX_SPAWN_SETPGROUP flag.
6326 resetids: bool(accept={int}) = False
6327 If the value is `true` the POSIX_SPAWN_RESETIDS will be activated.
6328 setsid: bool(accept={int}) = False
6329 If the value is `true` the POSIX_SPAWN_SETSID or POSIX_SPAWN_SETSID_NP will be activated.
6330 setsigmask: object(c_default='NULL') = ()
6331 The sigmask to use with the POSIX_SPAWN_SETSIGMASK flag.
6332 setsigdef: object(c_default='NULL') = ()
6333 The sigmask to use with the POSIX_SPAWN_SETSIGDEF flag.
6334 scheduler: object = NULL
6335 A tuple with the scheduler policy (optional) and parameters.
6336
6337 Execute the program specified by path in a new process.
6338 [clinic start generated code]*/
6339
6340 static PyObject *
6341 os_posix_spawn_impl(PyObject *module, path_t *path, PyObject *argv,
6342 PyObject *env, PyObject *file_actions,
6343 PyObject *setpgroup, int resetids, int setsid,
6344 PyObject *setsigmask, PyObject *setsigdef,
6345 PyObject *scheduler)
6346 /*[clinic end generated code: output=14a1098c566bc675 input=8c6305619a00ad04]*/
6347 {
6348 return py_posix_spawn(0, module, path, argv, env, file_actions,
6349 setpgroup, resetids, setsid, setsigmask, setsigdef,
6350 scheduler);
6351 }
6352 #endif /* HAVE_POSIX_SPAWN */
6353
6354
6355
6356 #ifdef HAVE_POSIX_SPAWNP
6357 /*[clinic input]
6358
6359 os.posix_spawnp
6360 path: path_t
6361 Path of executable file.
6362 argv: object
6363 Tuple or list of strings.
6364 env: object
6365 Dictionary of strings mapping to strings.
6366 /
6367 *
6368 file_actions: object(c_default='NULL') = ()
6369 A sequence of file action tuples.
6370 setpgroup: object = NULL
6371 The pgroup to use with the POSIX_SPAWN_SETPGROUP flag.
6372 resetids: bool(accept={int}) = False
6373 If the value is `True` the POSIX_SPAWN_RESETIDS will be activated.
6374 setsid: bool(accept={int}) = False
6375 If the value is `True` the POSIX_SPAWN_SETSID or POSIX_SPAWN_SETSID_NP will be activated.
6376 setsigmask: object(c_default='NULL') = ()
6377 The sigmask to use with the POSIX_SPAWN_SETSIGMASK flag.
6378 setsigdef: object(c_default='NULL') = ()
6379 The sigmask to use with the POSIX_SPAWN_SETSIGDEF flag.
6380 scheduler: object = NULL
6381 A tuple with the scheduler policy (optional) and parameters.
6382
6383 Execute the program specified by path in a new process.
6384 [clinic start generated code]*/
6385
6386 static PyObject *
6387 os_posix_spawnp_impl(PyObject *module, path_t *path, PyObject *argv,
6388 PyObject *env, PyObject *file_actions,
6389 PyObject *setpgroup, int resetids, int setsid,
6390 PyObject *setsigmask, PyObject *setsigdef,
6391 PyObject *scheduler)
6392 /*[clinic end generated code: output=7b9aaefe3031238d input=c1911043a22028da]*/
6393 {
6394 return py_posix_spawn(1, module, path, argv, env, file_actions,
6395 setpgroup, resetids, setsid, setsigmask, setsigdef,
6396 scheduler);
6397 }
6398 #endif /* HAVE_POSIX_SPAWNP */
6399
6400 #ifdef HAVE_RTPSPAWN
6401 static intptr_t
6402 _rtp_spawn(int mode, const char *rtpFileName, const char *argv[],
6403 const char *envp[])
6404 {
6405 RTP_ID rtpid;
6406 int status;
6407 pid_t res;
6408 int async_err = 0;
6409
6410 /* Set priority=100 and uStackSize=16 MiB (0x1000000) for new processes.
6411 uStackSize=0 cannot be used, the default stack size is too small for
6412 Python. */
6413 if (envp) {
6414 rtpid = rtpSpawn(rtpFileName, argv, envp,
6415 100, 0x1000000, 0, VX_FP_TASK);
6416 }
6417 else {
6418 rtpid = rtpSpawn(rtpFileName, argv, (const char **)environ,
6419 100, 0x1000000, 0, VX_FP_TASK);
6420 }
6421 if ((rtpid != RTP_ID_ERROR) && (mode == _P_WAIT)) {
6422 do {
6423 res = waitpid((pid_t)rtpid, &status, 0);
6424 } while (res < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
6425
6426 if (res < 0)
6427 return RTP_ID_ERROR;
6428 return ((intptr_t)status);
6429 }
6430 return ((intptr_t)rtpid);
6431 }
6432 #endif
6433
6434 #if defined(HAVE_SPAWNV) || defined(HAVE_WSPAWNV) || defined(HAVE_RTPSPAWN)
6435 /*[clinic input]
6436 os.spawnv
6437
6438 mode: int
6439 Mode of process creation.
6440 path: path_t
6441 Path of executable file.
6442 argv: object
6443 Tuple or list of strings.
6444 /
6445
6446 Execute the program specified by path in a new process.
6447 [clinic start generated code]*/
6448
6449 static PyObject *
6450 os_spawnv_impl(PyObject *module, int mode, path_t *path, PyObject *argv)
6451 /*[clinic end generated code: output=71cd037a9d96b816 input=43224242303291be]*/
6452 {
6453 EXECV_CHAR **argvlist;
6454 int i;
6455 Py_ssize_t argc;
6456 intptr_t spawnval;
6457 PyObject *(*getitem)(PyObject *, Py_ssize_t);
6458
6459 /* spawnv has three arguments: (mode, path, argv), where
6460 argv is a list or tuple of strings. */
6461
6462 if (PyList_Check(argv)) {
6463 argc = PyList_Size(argv);
6464 getitem = PyList_GetItem;
6465 }
6466 else if (PyTuple_Check(argv)) {
6467 argc = PyTuple_Size(argv);
6468 getitem = PyTuple_GetItem;
6469 }
6470 else {
6471 PyErr_SetString(PyExc_TypeError,
6472 "spawnv() arg 2 must be a tuple or list");
6473 return NULL;
6474 }
6475 if (argc == 0) {
6476 PyErr_SetString(PyExc_ValueError,
6477 "spawnv() arg 2 cannot be empty");
6478 return NULL;
6479 }
6480
6481 argvlist = PyMem_NEW(EXECV_CHAR *, argc+1);
6482 if (argvlist == NULL) {
6483 return PyErr_NoMemory();
6484 }
6485 for (i = 0; i < argc; i++) {
6486 if (!fsconvert_strdup((*getitem)(argv, i),
6487 &argvlist[i])) {
6488 free_string_array(argvlist, i);
6489 PyErr_SetString(
6490 PyExc_TypeError,
6491 "spawnv() arg 2 must contain only strings");
6492 return NULL;
6493 }
6494 if (i == 0 && !argvlist[0][0]) {
6495 free_string_array(argvlist, i + 1);
6496 PyErr_SetString(
6497 PyExc_ValueError,
6498 "spawnv() arg 2 first element cannot be empty");
6499 return NULL;
6500 }
6501 }
6502 argvlist[argc] = NULL;
6503
6504 #if !defined(HAVE_RTPSPAWN)
6505 if (mode == _OLD_P_OVERLAY)
6506 mode = _P_OVERLAY;
6507 #endif
6508
6509 if (PySys_Audit("os.spawn", "iOOO", mode, path->object, argv,
6510 Py_None) < 0) {
6511 free_string_array(argvlist, argc);
6512 return NULL;
6513 }
6514
6515 Py_BEGIN_ALLOW_THREADS
6516 _Py_BEGIN_SUPPRESS_IPH
6517 #ifdef HAVE_WSPAWNV
6518 spawnval = _wspawnv(mode, path->wide, argvlist);
6519 #elif defined(HAVE_RTPSPAWN)
6520 spawnval = _rtp_spawn(mode, path->narrow, (const char **)argvlist, NULL);
6521 #else
6522 spawnval = _spawnv(mode, path->narrow, argvlist);
6523 #endif
6524 _Py_END_SUPPRESS_IPH
6525 Py_END_ALLOW_THREADS
6526
6527 free_string_array(argvlist, argc);
6528
6529 if (spawnval == -1)
6530 return posix_error();
6531 else
6532 return Py_BuildValue(_Py_PARSE_INTPTR, spawnval);
6533 }
6534
6535 /*[clinic input]
6536 os.spawnve
6537
6538 mode: int
6539 Mode of process creation.
6540 path: path_t
6541 Path of executable file.
6542 argv: object
6543 Tuple or list of strings.
6544 env: object
6545 Dictionary of strings mapping to strings.
6546 /
6547
6548 Execute the program specified by path in a new process.
6549 [clinic start generated code]*/
6550
6551 static PyObject *
6552 os_spawnve_impl(PyObject *module, int mode, path_t *path, PyObject *argv,
6553 PyObject *env)
6554 /*[clinic end generated code: output=30fe85be56fe37ad input=3e40803ee7c4c586]*/
6555 {
6556 EXECV_CHAR **argvlist;
6557 EXECV_CHAR **envlist;
6558 PyObject *res = NULL;
6559 Py_ssize_t argc, i, envc;
6560 intptr_t spawnval;
6561 PyObject *(*getitem)(PyObject *, Py_ssize_t);
6562 Py_ssize_t lastarg = 0;
6563
6564 /* spawnve has four arguments: (mode, path, argv, env), where
6565 argv is a list or tuple of strings and env is a dictionary
6566 like posix.environ. */
6567
6568 if (PyList_Check(argv)) {
6569 argc = PyList_Size(argv);
6570 getitem = PyList_GetItem;
6571 }
6572 else if (PyTuple_Check(argv)) {
6573 argc = PyTuple_Size(argv);
6574 getitem = PyTuple_GetItem;
6575 }
6576 else {
6577 PyErr_SetString(PyExc_TypeError,
6578 "spawnve() arg 2 must be a tuple or list");
6579 goto fail_0;
6580 }
6581 if (argc == 0) {
6582 PyErr_SetString(PyExc_ValueError,
6583 "spawnve() arg 2 cannot be empty");
6584 goto fail_0;
6585 }
6586 if (!PyMapping_Check(env)) {
6587 PyErr_SetString(PyExc_TypeError,
6588 "spawnve() arg 3 must be a mapping object");
6589 goto fail_0;
6590 }
6591
6592 argvlist = PyMem_NEW(EXECV_CHAR *, argc+1);
6593 if (argvlist == NULL) {
6594 PyErr_NoMemory();
6595 goto fail_0;
6596 }
6597 for (i = 0; i < argc; i++) {
6598 if (!fsconvert_strdup((*getitem)(argv, i),
6599 &argvlist[i]))
6600 {
6601 lastarg = i;
6602 goto fail_1;
6603 }
6604 if (i == 0 && !argvlist[0][0]) {
6605 lastarg = i + 1;
6606 PyErr_SetString(
6607 PyExc_ValueError,
6608 "spawnv() arg 2 first element cannot be empty");
6609 goto fail_1;
6610 }
6611 }
6612 lastarg = argc;
6613 argvlist[argc] = NULL;
6614
6615 envlist = parse_envlist(env, &envc);
6616 if (envlist == NULL)
6617 goto fail_1;
6618
6619 #if !defined(HAVE_RTPSPAWN)
6620 if (mode == _OLD_P_OVERLAY)
6621 mode = _P_OVERLAY;
6622 #endif
6623
6624 if (PySys_Audit("os.spawn", "iOOO", mode, path->object, argv, env) < 0) {
6625 goto fail_2;
6626 }
6627
6628 Py_BEGIN_ALLOW_THREADS
6629 _Py_BEGIN_SUPPRESS_IPH
6630 #ifdef HAVE_WSPAWNV
6631 spawnval = _wspawnve(mode, path->wide, argvlist, envlist);
6632 #elif defined(HAVE_RTPSPAWN)
6633 spawnval = _rtp_spawn(mode, path->narrow, (const char **)argvlist,
6634 (const char **)envlist);
6635 #else
6636 spawnval = _spawnve(mode, path->narrow, argvlist, envlist);
6637 #endif
6638 _Py_END_SUPPRESS_IPH
6639 Py_END_ALLOW_THREADS
6640
6641 if (spawnval == -1)
6642 (void) posix_error();
6643 else
6644 res = Py_BuildValue(_Py_PARSE_INTPTR, spawnval);
6645
6646 fail_2:
6647 while (--envc >= 0) {
6648 PyMem_Free(envlist[envc]);
6649 }
6650 PyMem_Free(envlist);
6651 fail_1:
6652 free_string_array(argvlist, lastarg);
6653 fail_0:
6654 return res;
6655 }
6656
6657 #endif /* HAVE_SPAWNV */
6658
6659 #ifdef HAVE_FORK
6660
6661 /* Helper function to validate arguments.
6662 Returns 0 on success. non-zero on failure with a TypeError raised.
6663 If obj is non-NULL it must be callable. */
6664 static int
6665 14742 check_null_or_callable(PyObject *obj, const char* obj_name)
6666 {
6667
3/4
✓ Branch 0 taken 6198 times.
✓ Branch 1 taken 8544 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6198 times.
14742 if (obj && !PyCallable_Check(obj)) {
6668 PyErr_Format(PyExc_TypeError, "'%s' must be callable, not %s",
6669 obj_name, _PyType_Name(Py_TYPE(obj)));
6670 return -1;
6671 }
6672 14742 return 0;
6673 }
6674
6675 /*[clinic input]
6676 os.register_at_fork
6677
6678 *
6679 before: object=NULL
6680 A callable to be called in the parent before the fork() syscall.
6681 after_in_child: object=NULL
6682 A callable to be called in the child after fork().
6683 after_in_parent: object=NULL
6684 A callable to be called in the parent after fork().
6685
6686 Register callables to be called when forking a new process.
6687
6688 'before' callbacks are called in reverse order.
6689 'after_in_child' and 'after_in_parent' callbacks are called in order.
6690
6691 [clinic start generated code]*/
6692
6693 static PyObject *
6694 4914 os_register_at_fork_impl(PyObject *module, PyObject *before,
6695 PyObject *after_in_child, PyObject *after_in_parent)
6696 /*[clinic end generated code: output=5398ac75e8e97625 input=cd1187aa85d2312e]*/
6697 {
6698 PyInterpreterState *interp;
6699
6700
3/6
✓ Branch 0 taken 4272 times.
✓ Branch 1 taken 642 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4272 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
4914 if (!before && !after_in_child && !after_in_parent) {
6701 PyErr_SetString(PyExc_TypeError, "At least one argument is required.");
6702 return NULL;
6703 }
6704
2/4
✓ Branch 1 taken 4914 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4914 times.
✗ Branch 4 not taken.
9828 if (check_null_or_callable(before, "before") ||
6705
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4914 times.
9828 check_null_or_callable(after_in_child, "after_in_child") ||
6706 4914 check_null_or_callable(after_in_parent, "after_in_parent")) {
6707 return NULL;
6708 }
6709 4914 interp = _PyInterpreterState_GET();
6710
6711
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4914 times.
4914 if (register_at_forker(&interp->before_forkers, before)) {
6712 return NULL;
6713 }
6714
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4914 times.
4914 if (register_at_forker(&interp->after_forkers_child, after_in_child)) {
6715 return NULL;
6716 }
6717
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4914 times.
4914 if (register_at_forker(&interp->after_forkers_parent, after_in_parent)) {
6718 return NULL;
6719 }
6720 4914 Py_RETURN_NONE;
6721 }
6722 #endif /* HAVE_FORK */
6723
6724
6725 #ifdef HAVE_FORK1
6726 /*[clinic input]
6727 os.fork1
6728
6729 Fork a child process with a single multiplexed (i.e., not bound) thread.
6730
6731 Return 0 to child process and PID of child to parent process.
6732 [clinic start generated code]*/
6733
6734 static PyObject *
6735 os_fork1_impl(PyObject *module)
6736 /*[clinic end generated code: output=0de8e67ce2a310bc input=12db02167893926e]*/
6737 {
6738 pid_t pid;
6739
6740 if (!_Py_IsMainInterpreter(_PyInterpreterState_GET())) {
6741 PyErr_SetString(PyExc_RuntimeError, "fork not supported for subinterpreters");
6742 return NULL;
6743 }
6744 PyOS_BeforeFork();
6745 pid = fork1();
6746 if (pid == 0) {
6747 /* child: this clobbers and resets the import lock. */
6748 PyOS_AfterFork_Child();
6749 } else {
6750 /* parent: release the import lock. */
6751 PyOS_AfterFork_Parent();
6752 }
6753 if (pid == -1)
6754 return posix_error();
6755 return PyLong_FromPid(pid);
6756 }
6757 #endif /* HAVE_FORK1 */
6758
6759
6760 #ifdef HAVE_FORK
6761 /*[clinic input]
6762 os.fork
6763
6764 Fork a child process.
6765
6766 Return 0 to child process and PID of child to parent process.
6767 [clinic start generated code]*/
6768
6769 static PyObject *
6770 172 os_fork_impl(PyObject *module)
6771 /*[clinic end generated code: output=3626c81f98985d49 input=13c956413110eeaa]*/
6772 {
6773 pid_t pid;
6774 172 PyInterpreterState *interp = _PyInterpreterState_GET();
6775
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 172 times.
172 if (interp->config._isolated_interpreter) {
6776 PyErr_SetString(PyExc_RuntimeError,
6777 "fork not supported for isolated subinterpreters");
6778 return NULL;
6779 }
6780
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 172 times.
172 if (PySys_Audit("os.fork", NULL) < 0) {
6781 return NULL;
6782 }
6783 172 PyOS_BeforeFork();
6784 172 pid = fork();
6785
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 172 times.
172 if (pid == 0) {
6786 /* child: this clobbers and resets the import lock. */
6787 PyOS_AfterFork_Child();
6788 } else {
6789 /* parent: release the import lock. */
6790 172 PyOS_AfterFork_Parent();
6791 }
6792
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 172 times.
172 if (pid == -1)
6793 return posix_error();
6794 172 return PyLong_FromPid(pid);
6795 }
6796 #endif /* HAVE_FORK */
6797
6798
6799 #ifdef HAVE_SCHED_H
6800 #ifdef HAVE_SCHED_GET_PRIORITY_MAX
6801 /*[clinic input]
6802 os.sched_get_priority_max
6803
6804 policy: int
6805
6806 Get the maximum scheduling priority for policy.
6807 [clinic start generated code]*/
6808
6809 static PyObject *
6810 os_sched_get_priority_max_impl(PyObject *module, int policy)
6811 /*[clinic end generated code: output=9e465c6e43130521 input=2097b7998eca6874]*/
6812 {
6813 int max;
6814
6815 max = sched_get_priority_max(policy);
6816 if (max < 0)
6817 return posix_error();
6818 return PyLong_FromLong(max);
6819 }
6820
6821
6822 /*[clinic input]
6823 os.sched_get_priority_min
6824
6825 policy: int
6826
6827 Get the minimum scheduling priority for policy.
6828 [clinic start generated code]*/
6829
6830 static PyObject *
6831 os_sched_get_priority_min_impl(PyObject *module, int policy)
6832 /*[clinic end generated code: output=7595c1138cc47a6d input=21bc8fa0d70983bf]*/
6833 {
6834 int min = sched_get_priority_min(policy);
6835 if (min < 0)
6836 return posix_error();
6837 return PyLong_FromLong(min);
6838 }
6839 #endif /* HAVE_SCHED_GET_PRIORITY_MAX */
6840
6841
6842 #ifdef HAVE_SCHED_SETSCHEDULER
6843 /*[clinic input]
6844 os.sched_getscheduler
6845 pid: pid_t
6846 /
6847
6848 Get the scheduling policy for the process identified by pid.
6849
6850 Passing 0 for pid returns the scheduling policy for the calling process.
6851 [clinic start generated code]*/
6852
6853 static PyObject *
6854 os_sched_getscheduler_impl(PyObject *module, pid_t pid)
6855 /*[clinic end generated code: output=dce4c0bd3f1b34c8 input=8d99dac505485ac8]*/
6856 {
6857 int policy;
6858
6859 policy = sched_getscheduler(pid);
6860 if (policy < 0)
6861 return posix_error();
6862 return PyLong_FromLong(policy);
6863 }
6864 #endif /* HAVE_SCHED_SETSCHEDULER */
6865
6866
6867 #if defined(HAVE_SCHED_SETPARAM) || defined(HAVE_SCHED_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDPARAM)
6868 /*[clinic input]
6869 class os.sched_param "PyObject *" "SchedParamType"
6870
6871 @classmethod
6872 os.sched_param.__new__
6873
6874 sched_priority: object
6875 A scheduling parameter.
6876
6877 Currently has only one field: sched_priority
6878 [clinic start generated code]*/
6879
6880 static PyObject *
6881 os_sched_param_impl(PyTypeObject *type, PyObject *sched_priority)
6882 /*[clinic end generated code: output=48f4067d60f48c13 input=eb42909a2c0e3e6c]*/
6883 {
6884 PyObject *res;
6885
6886 res = PyStructSequence_New(type);
6887 if (!res)
6888 return NULL;
6889 Py_INCREF(sched_priority);
6890 PyStructSequence_SET_ITEM(res, 0, sched_priority);
6891 return res;
6892 }
6893
6894 PyDoc_VAR(os_sched_param__doc__);
6895
6896 static PyStructSequence_Field sched_param_fields[] = {
6897 {"sched_priority", "the scheduling priority"},
6898 {0}
6899 };
6900
6901 static PyStructSequence_Desc sched_param_desc = {
6902 "sched_param", /* name */
6903 os_sched_param__doc__, /* doc */
6904 sched_param_fields,
6905 1
6906 };
6907
6908 static int
6909 convert_sched_param(PyObject *module, PyObject *param, struct sched_param *res)
6910 {
6911 long priority;
6912
6913 if (!Py_IS_TYPE(param, (PyTypeObject *)get_posix_state(module)->SchedParamType)) {
6914 PyErr_SetString(PyExc_TypeError, "must have a sched_param object");
6915 return 0;
6916 }
6917 priority = PyLong_AsLong(PyStructSequence_GET_ITEM(param, 0));
6918 if (priority == -1 && PyErr_Occurred())
6919 return 0;
6920 if (priority > INT_MAX || priority < INT_MIN) {
6921 PyErr_SetString(PyExc_OverflowError, "sched_priority out of range");
6922 return 0;
6923 }
6924 res->sched_priority = Py_SAFE_DOWNCAST(priority, long, int);
6925 return 1;
6926 }
6927 #endif /* defined(HAVE_SCHED_SETPARAM) || defined(HAVE_SCHED_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDPARAM) */
6928
6929
6930 #ifdef HAVE_SCHED_SETSCHEDULER
6931 /*[clinic input]
6932 os.sched_setscheduler
6933
6934 pid: pid_t
6935 policy: int
6936 param as param_obj: object
6937 /
6938
6939 Set the scheduling policy for the process identified by pid.
6940
6941 If pid is 0, the calling process is changed.
6942 param is an instance of sched_param.
6943 [clinic start generated code]*/
6944
6945 static PyObject *
6946 os_sched_setscheduler_impl(PyObject *module, pid_t pid, int policy,
6947 PyObject *param_obj)
6948 /*[clinic end generated code: output=cde27faa55dc993e input=73013d731bd8fbe9]*/
6949 {
6950 struct sched_param param;
6951 if (!convert_sched_param(module, param_obj, &param)) {
6952 return NULL;
6953 }
6954
6955 /*
6956 ** sched_setscheduler() returns 0 in Linux, but the previous
6957 ** scheduling policy under Solaris/Illumos, and others.
6958 ** On error, -1 is returned in all Operating Systems.
6959 */
6960 if (sched_setscheduler(pid, policy, &param) == -1)
6961 return posix_error();
6962 Py_RETURN_NONE;
6963 }
6964 #endif /* HAVE_SCHED_SETSCHEDULER*/
6965
6966
6967 #ifdef HAVE_SCHED_SETPARAM
6968 /*[clinic input]
6969 os.sched_getparam
6970 pid: pid_t
6971 /
6972
6973 Returns scheduling parameters for the process identified by pid.
6974
6975 If pid is 0, returns parameters for the calling process.
6976 Return value is an instance of sched_param.
6977 [clinic start generated code]*/
6978
6979 static PyObject *
6980 os_sched_getparam_impl(PyObject *module, pid_t pid)
6981 /*[clinic end generated code: output=b194e8708dcf2db8 input=18a1ef9c2efae296]*/
6982 {
6983 struct sched_param param;
6984 PyObject *result;
6985 PyObject *priority;
6986
6987 if (sched_getparam(pid, &param))
6988 return posix_error();
6989 PyObject *SchedParamType = get_posix_state(module)->SchedParamType;
6990 result = PyStructSequence_New((PyTypeObject *)SchedParamType);
6991 if (!result)
6992 return NULL;
6993 priority = PyLong_FromLong(param.sched_priority);
6994 if (!priority) {
6995 Py_DECREF(result);
6996 return NULL;
6997 }
6998 PyStructSequence_SET_ITEM(result, 0, priority);
6999 return result;
7000 }
7001
7002
7003 /*[clinic input]
7004 os.sched_setparam
7005 pid: pid_t
7006 param as param_obj: object
7007 /
7008
7009 Set scheduling parameters for the process identified by pid.
7010
7011 If pid is 0, sets parameters for the calling process.
7012 param should be an instance of sched_param.
7013 [clinic start generated code]*/
7014
7015 static PyObject *
7016 os_sched_setparam_impl(PyObject *module, pid_t pid, PyObject *param_obj)
7017 /*[clinic end generated code: output=f19fe020a53741c1 input=27b98337c8b2dcc7]*/
7018 {
7019 struct sched_param param;
7020 if (!convert_sched_param(module, param_obj, &param)) {
7021 return NULL;
7022 }
7023
7024 if (sched_setparam(pid, &param))
7025 return posix_error();
7026 Py_RETURN_NONE;
7027 }
7028 #endif /* HAVE_SCHED_SETPARAM */
7029
7030
7031 #ifdef HAVE_SCHED_RR_GET_INTERVAL
7032 /*[clinic input]
7033 os.sched_rr_get_interval -> double
7034 pid: pid_t
7035 /
7036
7037 Return the round-robin quantum for the process identified by pid, in seconds.
7038
7039 Value returned is a float.
7040 [clinic start generated code]*/
7041
7042 static double
7043 os_sched_rr_get_interval_impl(PyObject *module, pid_t pid)
7044 /*[clinic end generated code: output=7e2d935833ab47dc input=2a973da15cca6fae]*/
7045 {
7046 struct timespec interval;
7047 if (sched_rr_get_interval(pid, &interval)) {
7048 posix_error();
7049 return -1.0;
7050 }
7051 #ifdef _Py_MEMORY_SANITIZER
7052 __msan_unpoison(&interval, sizeof(interval));
7053 #endif
7054 return (double)interval.tv_sec + 1e-9*interval.tv_nsec;
7055 }
7056 #endif /* HAVE_SCHED_RR_GET_INTERVAL */
7057
7058
7059 /*[clinic input]
7060 os.sched_yield
7061
7062 Voluntarily relinquish the CPU.
7063 [clinic start generated code]*/
7064
7065 static PyObject *
7066 os_sched_yield_impl(PyObject *module)
7067 /*[clinic end generated code: output=902323500f222cac input=e54d6f98189391d4]*/
7068 {
7069 if (sched_yield())
7070 return posix_error();
7071 Py_RETURN_NONE;
7072 }
7073
7074 #ifdef HAVE_SCHED_SETAFFINITY
7075 /* The minimum number of CPUs allocated in a cpu_set_t */
7076 static const int NCPUS_START = sizeof(unsigned long) * CHAR_BIT;
7077
7078 /*[clinic input]
7079 os.sched_setaffinity
7080 pid: pid_t
7081 mask : object
7082 /
7083
7084 Set the CPU affinity of the process identified by pid to mask.
7085
7086 mask should be an iterable of integers identifying CPUs.
7087 [clinic start generated code]*/
7088
7089 static PyObject *
7090 os_sched_setaffinity_impl(PyObject *module, pid_t pid, PyObject *mask)
7091 /*[clinic end generated code: output=882d7dd9a229335b input=a0791a597c7085ba]*/
7092 {
7093 int ncpus;
7094 size_t setsize;
7095 cpu_set_t *cpu_set = NULL;
7096 PyObject *iterator = NULL, *item;
7097
7098 iterator = PyObject_GetIter(mask);
7099 if (iterator == NULL)
7100 return NULL;
7101
7102 ncpus = NCPUS_START;
7103 setsize = CPU_ALLOC_SIZE(ncpus);
7104 cpu_set = CPU_ALLOC(ncpus);
7105 if (cpu_set == NULL) {
7106 PyErr_NoMemory();
7107 goto error;
7108 }
7109 CPU_ZERO_S(setsize, cpu_set);
7110
7111 while ((item = PyIter_Next(iterator))) {
7112 long cpu;
7113 if (!PyLong_Check(item)) {
7114 PyErr_Format(PyExc_TypeError,
7115 "expected an iterator of ints, "
7116 "but iterator yielded %R",
7117 Py_TYPE(item));
7118 Py_DECREF(item);
7119 goto error;
7120 }
7121 cpu = PyLong_AsLong(item);
7122 Py_DECREF(item);
7123 if (cpu < 0) {
7124 if (!PyErr_Occurred())
7125 PyErr_SetString(PyExc_ValueError, "negative CPU number");
7126 goto error;
7127 }
7128 if (cpu > INT_MAX - 1) {
7129 PyErr_SetString(PyExc_OverflowError, "CPU number too large");
7130 goto error;
7131 }
7132 if (cpu >= ncpus) {
7133 /* Grow CPU mask to fit the CPU number */
7134 int newncpus = ncpus;
7135 cpu_set_t *newmask;
7136 size_t newsetsize;
7137 while (newncpus <= cpu) {
7138 if (newncpus > INT_MAX / 2)
7139 newncpus = cpu + 1;
7140 else
7141 newncpus = newncpus * 2;
7142 }
7143 newmask = CPU_ALLOC(newncpus);
7144 if (newmask == NULL) {
7145 PyErr_NoMemory();
7146 goto error;
7147 }
7148 newsetsize = CPU_ALLOC_SIZE(newncpus);
7149 CPU_ZERO_S(newsetsize, newmask);
7150 memcpy(newmask, cpu_set, setsize);
7151 CPU_FREE(cpu_set);
7152 setsize = newsetsize;
7153 cpu_set = newmask;
7154 ncpus = newncpus;
7155 }
7156 CPU_SET_S(cpu, setsize, cpu_set);
7157 }
7158 if (PyErr_Occurred()) {
7159 goto error;
7160 }
7161 Py_CLEAR(iterator);
7162
7163 if (sched_setaffinity(pid, setsize, cpu_set)) {
7164 posix_error();
7165 goto error;
7166 }
7167 CPU_FREE(cpu_set);
7168 Py_RETURN_NONE;
7169
7170 error:
7171 if (cpu_set)
7172 CPU_FREE(cpu_set);
7173 Py_XDECREF(iterator);
7174 return NULL;
7175 }
7176
7177
7178 /*[clinic input]
7179 os.sched_getaffinity
7180 pid: pid_t
7181 /
7182
7183 Return the affinity of the process identified by pid (or the current process if zero).
7184
7185 The affinity is returned as a set of CPU identifiers.
7186 [clinic start generated code]*/
7187
7188 static PyObject *
7189 1512 os_sched_getaffinity_impl(PyObject *module, pid_t pid)
7190 /*[clinic end generated code: output=f726f2c193c17a4f input=983ce7cb4a565980]*/
7191 {
7192 int cpu, ncpus, count;
7193 size_t setsize;
7194 1512 cpu_set_t *mask = NULL;
7195 1512 PyObject *res = NULL;
7196
7197 1512 ncpus = NCPUS_START;
7198 while (1) {
7199 1512 setsize = CPU_ALLOC_SIZE(ncpus);
7200 1512 mask = CPU_ALLOC(ncpus);
7201
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1512 times.
1512 if (mask == NULL)
7202 return PyErr_NoMemory();
7203
1/2
✓ Branch 1 taken 1512 times.
✗ Branch 2 not taken.
1512 if (sched_getaffinity(pid, setsize, mask) == 0)
7204 1512 break;
7205 CPU_FREE(mask);
7206 if (errno != EINVAL)
7207 return posix_error();
7208 if (ncpus > INT_MAX / 2) {
7209 PyErr_SetString(PyExc_OverflowError, "could not allocate "
7210 "a large enough CPU set");
7211 return NULL;
7212 }
7213 ncpus = ncpus * 2;
7214 }
7215
7216 1512 res = PySet_New(NULL);
7217
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1512 times.
1512 if (res == NULL)
7218 goto error;
7219
2/2
✓ Branch 1 taken 24192 times.
✓ Branch 2 taken 1512 times.
25704 for (cpu = 0, count = CPU_COUNT_S(setsize, mask); count; cpu++) {
7220
3/6
✓ Branch 0 taken 24192 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24192 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 24192 times.
✗ Branch 5 not taken.
24192 if (CPU_ISSET_S(cpu, setsize, mask)) {
7221 24192 PyObject *cpu_num = PyLong_FromLong(cpu);
7222 24192 --count;
7223
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24192 times.
24192 if (cpu_num == NULL)
7224 goto error;
7225
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 24192 times.
24192 if (PySet_Add(res, cpu_num)) {
7226 Py_DECREF(cpu_num);
7227 goto error;
7228 }
7229 24192 Py_DECREF(cpu_num);
7230 }
7231 }
7232 1512 CPU_FREE(mask);
7233 1512 return res;
7234
7235 error:
7236 if (mask)
7237 CPU_FREE(mask);
7238 Py_XDECREF(res);
7239 return NULL;
7240 }
7241
7242 #endif /* HAVE_SCHED_SETAFFINITY */
7243
7244 #endif /* HAVE_SCHED_H */
7245
7246
7247 /* AIX uses /dev/ptc but is otherwise the same as /dev/ptmx */
7248 #if defined(HAVE_DEV_PTC) && !defined(HAVE_DEV_PTMX)
7249 # define DEV_PTY_FILE "/dev/ptc"
7250 # define HAVE_DEV_PTMX
7251 #else
7252 # define DEV_PTY_FILE "/dev/ptmx"
7253 #endif
7254
7255 #if defined(HAVE_OPENPTY) || defined(HAVE_FORKPTY) || defined(HAVE_LOGIN_TTY) || defined(HAVE_DEV_PTMX)
7256 #ifdef HAVE_PTY_H
7257 #include <pty.h>
7258 #ifdef HAVE_UTMP_H
7259 #include <utmp.h>
7260 #endif /* HAVE_UTMP_H */
7261 #elif defined(HAVE_LIBUTIL_H)
7262 #include <libutil.h>
7263 #elif defined(HAVE_UTIL_H)
7264 #include <util.h>
7265 #endif /* HAVE_PTY_H */
7266 #ifdef HAVE_STROPTS_H
7267 #include <stropts.h>
7268 #endif
7269 #endif /* defined(HAVE_OPENPTY) || defined(HAVE_FORKPTY) || defined(HAVE_LOGIN_TTY) || defined(HAVE_DEV_PTMX) */
7270
7271
7272 #if defined(HAVE_OPENPTY) || defined(HAVE__GETPTY) || defined(HAVE_DEV_PTMX)
7273 /*[clinic input]
7274 os.openpty
7275
7276 Open a pseudo-terminal.
7277
7278 Return a tuple of (master_fd, slave_fd) containing open file descriptors
7279 for both the master and slave ends.
7280 [clinic start generated code]*/
7281
7282 static PyObject *
7283 os_openpty_impl(PyObject *module)
7284 /*[clinic end generated code: output=98841ce5ec9cef3c input=f3d99fd99e762907]*/
7285 {
7286 int master_fd = -1, slave_fd = -1;
7287 #ifndef HAVE_OPENPTY
7288 char * slave_name;
7289 #endif
7290 #if defined(HAVE_DEV_PTMX) && !defined(HAVE_OPENPTY) && !defined(HAVE__GETPTY)
7291 PyOS_sighandler_t sig_saved;
7292 #if defined(__sun) && defined(__SVR4)
7293 extern char *ptsname(int fildes);
7294 #endif
7295 #endif
7296
7297 #ifdef HAVE_OPENPTY
7298 if (openpty(&master_fd, &slave_fd, NULL, NULL, NULL) != 0)
7299 goto posix_error;
7300
7301 if (_Py_set_inheritable(master_fd, 0, NULL) < 0)
7302 goto error;
7303 if (_Py_set_inheritable(slave_fd, 0, NULL) < 0)
7304 goto error;
7305
7306 #elif defined(HAVE__GETPTY)
7307 slave_name = _getpty(&master_fd, O_RDWR, 0666, 0);
7308 if (slave_name == NULL)
7309 goto posix_error;
7310 if (_Py_set_inheritable(master_fd, 0, NULL) < 0)
7311 goto error;
7312
7313 slave_fd = _Py_open(slave_name, O_RDWR);
7314 if (slave_fd < 0)
7315 goto error;
7316
7317 #else
7318 master_fd = open(DEV_PTY_FILE, O_RDWR | O_NOCTTY); /* open master */
7319 if (master_fd < 0)
7320 goto posix_error;
7321
7322 sig_saved = PyOS_setsig(SIGCHLD, SIG_DFL);
7323
7324 /* change permission of slave */
7325 if (grantpt(master_fd) < 0) {
7326 PyOS_setsig(SIGCHLD, sig_saved);
7327 goto posix_error;
7328 }
7329
7330 /* unlock slave */
7331 if (unlockpt(master_fd) < 0) {
7332 PyOS_setsig(SIGCHLD, sig_saved);
7333 goto posix_error;
7334 }
7335
7336 PyOS_setsig(SIGCHLD, sig_saved);
7337
7338 slave_name = ptsname(master_fd); /* get name of slave */
7339 if (slave_name == NULL)
7340 goto posix_error;
7341
7342 slave_fd = _Py_open(slave_name, O_RDWR | O_NOCTTY); /* open slave */
7343 if (slave_fd == -1)
7344 goto error;
7345
7346 if (_Py_set_inheritable(master_fd, 0, NULL) < 0)
7347 goto posix_error;
7348
7349 #if !defined(__CYGWIN__) && !defined(__ANDROID__) && !defined(HAVE_DEV_PTC)
7350 ioctl(slave_fd, I_PUSH, "ptem"); /* push ptem */
7351 ioctl(slave_fd, I_PUSH, "ldterm"); /* push ldterm */
7352 #ifndef __hpux
7353 ioctl(slave_fd, I_PUSH, "ttcompat"); /* push ttcompat */
7354 #endif /* __hpux */
7355 #endif /* HAVE_CYGWIN */
7356 #endif /* HAVE_OPENPTY */
7357
7358 return Py_BuildValue("(ii)", master_fd, slave_fd);
7359
7360 posix_error:
7361 posix_error();
7362 error:
7363 if (master_fd != -1)
7364 close(master_fd);
7365 if (slave_fd != -1)
7366 close(slave_fd);
7367 return NULL;
7368 }
7369 #endif /* defined(HAVE_OPENPTY) || defined(HAVE__GETPTY) || defined(HAVE_DEV_PTMX) */
7370
7371
7372 #if defined(HAVE_SETSID) && defined(TIOCSCTTY)
7373 #define HAVE_FALLBACK_LOGIN_TTY 1
7374 #endif /* defined(HAVE_SETSID) && defined(TIOCSCTTY) */
7375
7376 #if defined(HAVE_LOGIN_TTY) || defined(HAVE_FALLBACK_LOGIN_TTY)
7377 /*[clinic input]
7378 os.login_tty
7379
7380 fd: fildes
7381 /
7382
7383 Prepare the tty of which fd is a file descriptor for a new login session.
7384
7385 Make the calling process a session leader; make the tty the
7386 controlling tty, the stdin, the stdout, and the stderr of the
7387 calling process; close fd.
7388 [clinic start generated code]*/
7389
7390 static PyObject *
7391 os_login_tty_impl(PyObject *module, int fd)
7392 /*[clinic end generated code: output=495a79911b4cc1bc input=5f298565099903a2]*/
7393 {
7394 #ifdef HAVE_LOGIN_TTY
7395 if (login_tty(fd) == -1) {
7396 return posix_error();
7397 }
7398 #else /* defined(HAVE_FALLBACK_LOGIN_TTY) */
7399 /* Establish a new session. */
7400 if (setsid() == -1) {
7401 return posix_error();
7402 }
7403
7404 /* The tty becomes the controlling terminal. */
7405 if (ioctl(fd, TIOCSCTTY, (char *)NULL) == -1) {
7406 return posix_error();
7407 }
7408
7409 /* The tty becomes stdin/stdout/stderr */
7410 if (dup2(fd, 0) == -1 || dup2(fd, 1) == -1 || dup2(fd, 2) == -1) {
7411 return posix_error();
7412 }
7413 if (fd > 2) {
7414 close(fd);
7415 }
7416 #endif /* HAVE_LOGIN_TTY */
7417 Py_RETURN_NONE;
7418 }
7419 #endif /* defined(HAVE_LOGIN_TTY) || defined(HAVE_FALLBACK_LOGIN_TTY) */
7420
7421
7422 #ifdef HAVE_FORKPTY
7423 /*[clinic input]
7424 os.forkpty
7425
7426 Fork a new process with a new pseudo-terminal as controlling tty.
7427
7428 Returns a tuple of (pid, master_fd).
7429 Like fork(), return pid of 0 to the child process,
7430 and pid of child to the parent process.
7431 To both, return fd of newly opened pseudo-terminal.
7432 [clinic start generated code]*/
7433
7434 static PyObject *
7435 os_forkpty_impl(PyObject *module)
7436 /*[clinic end generated code: output=60d0a5c7512e4087 input=f1f7f4bae3966010]*/
7437 {
7438 int master_fd = -1;
7439 pid_t pid;
7440
7441 if (!_Py_IsMainInterpreter(_PyInterpreterState_GET())) {
7442 PyErr_SetString(PyExc_RuntimeError, "fork not supported for subinterpreters");
7443 return NULL;
7444 }
7445 if (PySys_Audit("os.forkpty", NULL) < 0) {
7446 return NULL;
7447 }
7448 PyOS_BeforeFork();
7449 pid = forkpty(&master_fd, NULL, NULL, NULL);
7450 if (pid == 0) {
7451 /* child: this clobbers and resets the import lock. */
7452 PyOS_AfterFork_Child();
7453 } else {
7454 /* parent: release the import lock. */
7455 PyOS_AfterFork_Parent();
7456 }
7457 if (pid == -1) {
7458 return posix_error();
7459 }
7460 return Py_BuildValue("(Ni)", PyLong_FromPid(pid), master_fd);
7461 }
7462 #endif /* HAVE_FORKPTY */
7463
7464
7465 #ifdef HAVE_GETEGID
7466 /*[clinic input]
7467 os.getegid
7468
7469 Return the current process's effective group id.
7470 [clinic start generated code]*/
7471
7472 static PyObject *
7473 4 os_getegid_impl(PyObject *module)
7474 /*[clinic end generated code: output=67d9be7ac68898a2 input=1596f79ad1107d5d]*/
7475 {
7476 4 return _PyLong_FromGid(getegid());
7477 }
7478 #endif /* HAVE_GETEGID */
7479
7480
7481 #ifdef HAVE_GETEUID
7482 /*[clinic input]
7483 os.geteuid
7484
7485 Return the current process's effective user id.
7486 [clinic start generated code]*/
7487
7488 static PyObject *
7489 234 os_geteuid_impl(PyObject *module)
7490 /*[clinic end generated code: output=ea1b60f0d6abb66e input=4644c662d3bd9f19]*/
7491 {
7492 234 return _PyLong_FromUid(geteuid());
7493 }
7494 #endif /* HAVE_GETEUID */
7495
7496
7497 #ifdef HAVE_GETGID
7498 /*[clinic input]
7499 os.getgid
7500
7501 Return the current process's group id.
7502 [clinic start generated code]*/
7503
7504 static PyObject *
7505 4 os_getgid_impl(PyObject *module)
7506 /*[clinic end generated code: output=4f28ebc9d3e5dfcf input=58796344cd87c0f6]*/
7507 {
7508 4 return _PyLong_FromGid(getgid());
7509 }
7510 #endif /* HAVE_GETGID */
7511
7512
7513 #ifdef HAVE_GETPID
7514 /*[clinic input]
7515 os.getpid
7516
7517 Return the current process id.
7518 [clinic start generated code]*/
7519
7520 static PyObject *
7521 225493 os_getpid_impl(PyObject *module)
7522 /*[clinic end generated code: output=9ea6fdac01ed2b3c input=5a9a00f0ab68aa00]*/
7523 {
7524 225493 return PyLong_FromPid(getpid());
7525 }
7526 #endif /* HAVE_GETPID */
7527
7528 #ifdef NGROUPS_MAX
7529 #define MAX_GROUPS NGROUPS_MAX
7530 #else
7531 /* defined to be 16 on Solaris7, so this should be a small number */
7532 #define MAX_GROUPS 64
7533 #endif
7534
7535 #ifdef HAVE_GETGROUPLIST
7536
7537 #ifdef __APPLE__
7538 /*[clinic input]
7539 os.getgrouplist
7540
7541 user: str
7542 username to lookup
7543 group as basegid: int
7544 base group id of the user
7545 /
7546
7547 Returns a list of groups to which a user belongs.
7548 [clinic start generated code]*/
7549
7550 static PyObject *
7551 os_getgrouplist_impl(PyObject *module, const char *user, int basegid)
7552 /*[clinic end generated code: output=6e734697b8c26de0 input=f8d870374b09a490]*/
7553 #else
7554 /*[clinic input]
7555 os.getgrouplist
7556
7557 user: str
7558 username to lookup
7559 group as basegid: gid_t
7560 base group id of the user
7561 /
7562
7563 Returns a list of groups to which a user belongs.
7564 [clinic start generated code]*/
7565
7566 static PyObject *
7567 os_getgrouplist_impl(PyObject *module, const char *user, gid_t basegid)
7568 /*[clinic end generated code: output=0ebd7fb70115575b input=cc61d5c20b08958d]*/
7569 #endif
7570 {
7571 int i, ngroups;
7572 PyObject *list;
7573 #ifdef __APPLE__
7574 int *groups;
7575 #else
7576 gid_t *groups;
7577 #endif
7578
7579 /*
7580 * NGROUPS_MAX is defined by POSIX.1 as the maximum
7581 * number of supplimental groups a users can belong to.
7582 * We have to increment it by one because
7583 * getgrouplist() returns both the supplemental groups
7584 * and the primary group, i.e. all of the groups the
7585 * user belongs to.
7586 */
7587 ngroups = 1 + MAX_GROUPS;
7588
7589 while (1) {
7590 #ifdef __APPLE__
7591 groups = PyMem_New(int, ngroups);
7592 #else
7593 groups = PyMem_New(gid_t, ngroups);
7594 #endif
7595 if (groups == NULL) {
7596 return PyErr_NoMemory();
7597 }
7598
7599 int old_ngroups = ngroups;
7600 if (getgrouplist(user, basegid, groups, &ngroups) != -1) {
7601 /* Success */
7602 break;
7603 }
7604
7605 /* getgrouplist() fails if the group list is too small */
7606 PyMem_Free(groups);
7607
7608 if (ngroups > old_ngroups) {
7609 /* If the group list is too small, the glibc implementation of
7610 getgrouplist() sets ngroups to the total number of groups and
7611 returns -1. */
7612 }
7613 else {
7614 /* Double the group list size */
7615 if (ngroups > INT_MAX / 2) {
7616 return PyErr_NoMemory();
7617 }
7618 ngroups *= 2;
7619 }
7620
7621 /* Retry getgrouplist() with a larger group list */
7622 }
7623
7624 #ifdef _Py_MEMORY_SANITIZER
7625 /* Clang memory sanitizer libc intercepts don't know getgrouplist. */
7626 __msan_unpoison(&ngroups, sizeof(ngroups));
7627 __msan_unpoison(groups, ngroups*sizeof(*groups));
7628 #endif
7629
7630 list = PyList_New(ngroups);
7631 if (list == NULL) {
7632 PyMem_Free(groups);
7633 return NULL;
7634 }
7635
7636 for (i = 0; i < ngroups; i++) {
7637 #ifdef __APPLE__
7638 PyObject *o = PyLong_FromUnsignedLong((unsigned long)groups[i]);
7639 #else
7640 PyObject *o = _PyLong_FromGid(groups[i]);
7641 #endif
7642 if (o == NULL) {
7643 Py_DECREF(list);
7644 PyMem_Free(groups);
7645 return NULL;
7646 }
7647 PyList_SET_ITEM(list, i, o);
7648 }
7649
7650 PyMem_Free(groups);
7651
7652 return list;
7653 }
7654 #endif /* HAVE_GETGROUPLIST */
7655
7656
7657 #ifdef HAVE_GETGROUPS
7658 /*[clinic input]
7659 os.getgroups
7660
7661 Return list of supplemental group IDs for the process.
7662 [clinic start generated code]*/
7663
7664 static PyObject *
7665 os_getgroups_impl(PyObject *module)
7666 /*[clinic end generated code: output=42b0c17758561b56 input=d3f109412e6a155c]*/
7667 {
7668 // Call getgroups with length 0 to get the actual number of groups
7669 int n = getgroups(0, NULL);
7670 if (n < 0) {
7671 return posix_error();
7672 }
7673
7674 if (n == 0) {
7675 return PyList_New(0);
7676 }
7677
7678 gid_t *grouplist = PyMem_New(gid_t, n);
7679 if (grouplist == NULL) {
7680 return PyErr_NoMemory();
7681 }
7682
7683 n = getgroups(n, grouplist);
7684 if (n == -1) {
7685 PyMem_Free(grouplist);
7686 return posix_error();
7687 }
7688
7689 PyObject *result = PyList_New(n);
7690 if (result == NULL) {
7691 goto error;
7692 }
7693
7694 for (int i = 0; i < n; ++i) {
7695 PyObject *group = _PyLong_FromGid(grouplist[i]);
7696 if (group == NULL) {
7697 goto error;
7698 }
7699 PyList_SET_ITEM(result, i, group);
7700 }
7701 PyMem_Free(grouplist);
7702
7703 return result;
7704
7705 error:
7706 PyMem_Free(grouplist);
7707 Py_XDECREF(result);
7708 return NULL;
7709 }
7710 #endif /* HAVE_GETGROUPS */
7711
7712 #ifdef HAVE_INITGROUPS
7713 #ifdef __APPLE__
7714 /*[clinic input]
7715 os.initgroups
7716
7717 username as oname: FSConverter
7718 gid: int
7719 /
7720
7721 Initialize the group access list.
7722
7723 Call the system initgroups() to initialize the group access list with all of
7724 the groups of which the specified username is a member, plus the specified
7725 group id.
7726 [clinic start generated code]*/
7727
7728 static PyObject *
7729 os_initgroups_impl(PyObject *module, PyObject *oname, int gid)
7730 /*[clinic end generated code: output=7f074d30a425fd3a input=df3d54331b0af204]*/
7731 #else
7732 /*[clinic input]
7733 os.initgroups
7734
7735 username as oname: FSConverter
7736 gid: gid_t
7737 /
7738
7739 Initialize the group access list.
7740
7741 Call the system initgroups() to initialize the group access list with all of
7742 the groups of which the specified username is a member, plus the specified
7743 group id.
7744 [clinic start generated code]*/
7745
7746 static PyObject *
7747 os_initgroups_impl(PyObject *module, PyObject *oname, gid_t gid)
7748 /*[clinic end generated code: output=59341244521a9e3f input=0cb91bdc59a4c564]*/
7749 #endif
7750 {
7751 const char *username = PyBytes_AS_STRING(oname);
7752
7753 if (initgroups(username, gid) == -1)
7754 return PyErr_SetFromErrno(PyExc_OSError);
7755
7756 Py_RETURN_NONE;
7757 }
7758 #endif /* HAVE_INITGROUPS */
7759
7760
7761 #ifdef HAVE_GETPGID
7762 /*[clinic input]
7763 os.getpgid
7764
7765 pid: pid_t
7766
7767 Call the system call getpgid(), and return the result.
7768 [clinic start generated code]*/
7769
7770 static PyObject *
7771 os_getpgid_impl(PyObject *module, pid_t pid)
7772 /*[clinic end generated code: output=1db95a97be205d18 input=39d710ae3baaf1c7]*/
7773 {
7774 pid_t pgid = getpgid(pid);
7775 if (pgid < 0)
7776 return posix_error();
7777 return PyLong_FromPid(pgid);
7778 }
7779 #endif /* HAVE_GETPGID */
7780
7781
7782 #ifdef HAVE_GETPGRP
7783 /*[clinic input]
7784 os.getpgrp
7785
7786 Return the current process group id.
7787 [clinic start generated code]*/
7788
7789 static PyObject *
7790 os_getpgrp_impl(PyObject *module)
7791 /*[clinic end generated code: output=c4fc381e51103cf3 input=6846fb2bb9a3705e]*/
7792 {
7793 #ifdef GETPGRP_HAVE_ARG
7794 return PyLong_FromPid(getpgrp(0));
7795 #else /* GETPGRP_HAVE_ARG */
7796 return PyLong_FromPid(getpgrp());
7797 #endif /* GETPGRP_HAVE_ARG */
7798 }
7799 #endif /* HAVE_GETPGRP */
7800
7801
7802 #ifdef HAVE_SETPGRP
7803 /*[clinic input]
7804 os.setpgrp
7805
7806 Make the current process the leader of its process group.
7807 [clinic start generated code]*/
7808
7809 static PyObject *
7810 os_setpgrp_impl(PyObject *module)
7811 /*[clinic end generated code: output=2554735b0a60f0a0 input=1f0619fcb5731e7e]*/
7812 {
7813 #ifdef SETPGRP_HAVE_ARG
7814 if (setpgrp(0, 0) < 0)
7815 #else /* SETPGRP_HAVE_ARG */
7816 if (setpgrp() < 0)
7817 #endif /* SETPGRP_HAVE_ARG */
7818 return posix_error();
7819 Py_RETURN_NONE;
7820 }
7821 #endif /* HAVE_SETPGRP */
7822
7823 #ifdef HAVE_GETPPID
7824
7825 #ifdef MS_WINDOWS
7826 #include <tlhelp32.h>
7827
7828 static PyObject*
7829 win32_getppid()
7830 {
7831 HANDLE snapshot;
7832 pid_t mypid;
7833 PyObject* result = NULL;
7834 BOOL have_record;
7835 PROCESSENTRY32 pe;
7836
7837 mypid = getpid(); /* This function never fails */
7838
7839 snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
7840 if (snapshot == INVALID_HANDLE_VALUE)
7841 return PyErr_SetFromWindowsErr(GetLastError());
7842
7843 pe.dwSize = sizeof(pe);
7844 have_record = Process32First(snapshot, &pe);
7845 while (have_record) {
7846 if (mypid == (pid_t)pe.th32ProcessID) {
7847 /* We could cache the ulong value in a static variable. */
7848 result = PyLong_FromPid((pid_t)pe.th32ParentProcessID);
7849 break;
7850 }
7851
7852 have_record = Process32Next(snapshot, &pe);
7853 }
7854
7855 /* If our loop exits and our pid was not found (result will be NULL)
7856 * then GetLastError will return ERROR_NO_MORE_FILES. This is an
7857 * error anyway, so let's raise it. */
7858 if (!result)
7859 result = PyErr_SetFromWindowsErr(GetLastError());
7860
7861 CloseHandle(snapshot);
7862
7863 return result;
7864 }
7865 #endif /*MS_WINDOWS*/
7866
7867
7868 /*[clinic input]
7869 os.getppid
7870
7871 Return the parent's process id.
7872
7873 If the parent process has already exited, Windows machines will still
7874 return its id; others systems will return the id of the 'init' process (1).
7875 [clinic start generated code]*/
7876
7877 static PyObject *
7878 os_getppid_impl(PyObject *module)
7879 /*[clinic end generated code: output=43b2a946a8c603b4 input=e637cb87539c030e]*/
7880 {
7881 #ifdef MS_WINDOWS
7882 return win32_getppid();
7883 #else
7884 return PyLong_FromPid(getppid());
7885 #endif
7886 }
7887 #endif /* HAVE_GETPPID */
7888
7889
7890 #ifdef HAVE_GETLOGIN
7891 /*[clinic input]
7892 os.getlogin
7893
7894 Return the actual login name.
7895 [clinic start generated code]*/
7896
7897 static PyObject *
7898 os_getlogin_impl(PyObject *module)
7899 /*[clinic end generated code: output=a32e66a7e5715dac input=2a21ab1e917163df]*/
7900 {
7901 PyObject *result = NULL;
7902 #ifdef MS_WINDOWS
7903 wchar_t user_name[UNLEN + 1];
7904 DWORD num_chars = Py_ARRAY_LENGTH(user_name);
7905
7906 if (GetUserNameW(user_name, &num_chars)) {
7907 /* num_chars is the number of unicode chars plus null terminator */
7908 result = PyUnicode_FromWideChar(user_name, num_chars - 1);
7909 }
7910 else
7911 result = PyErr_SetFromWindowsErr(GetLastError());
7912 #else
7913 char *name;
7914 int old_errno = errno;
7915
7916 errno = 0;
7917 name = getlogin();
7918 if (name == NULL) {
7919 if (errno)
7920 posix_error();
7921 else
7922 PyErr_SetString(PyExc_OSError, "unable to determine login name");
7923 }
7924 else
7925 result = PyUnicode_DecodeFSDefault(name);
7926 errno = old_errno;
7927 #endif
7928 return result;
7929 }
7930 #endif /* HAVE_GETLOGIN */
7931
7932
7933 #ifdef HAVE_GETUID
7934 /*[clinic input]
7935 os.getuid
7936
7937 Return the current process's user id.
7938 [clinic start generated code]*/
7939
7940 static PyObject *
7941 4 os_getuid_impl(PyObject *module)
7942 /*[clinic end generated code: output=415c0b401ebed11a input=b53c8b35f110a516]*/
7943 {
7944 4 return _PyLong_FromUid(getuid());
7945 }
7946 #endif /* HAVE_GETUID */
7947
7948
7949 #ifdef MS_WINDOWS
7950 #define HAVE_KILL
7951 #endif /* MS_WINDOWS */
7952
7953 #ifdef HAVE_KILL
7954 /*[clinic input]
7955 os.kill
7956
7957 pid: pid_t
7958 signal: Py_ssize_t
7959 /
7960
7961 Kill a process with a signal.
7962 [clinic start generated code]*/
7963
7964 static PyObject *
7965 os_kill_impl(PyObject *module, pid_t pid, Py_ssize_t signal)
7966 /*[clinic end generated code: output=8e346a6701c88568 input=61a36b86ca275ab9]*/
7967 {
7968 if (PySys_Audit("os.kill", "in", pid, signal) < 0) {
7969 return NULL;
7970 }
7971 #ifndef MS_WINDOWS
7972 if (kill(pid, (int)signal) == -1) {
7973 return posix_error();
7974 }
7975
7976 // Check immediately if the signal was sent to the current process.
7977 // Don't micro-optimize pid == getpid(), since PyErr_SetString() check
7978 // is cheap.
7979 if (PyErr_CheckSignals()) {
7980 return NULL;
7981 }
7982
7983 Py_RETURN_NONE;
7984 #else /* !MS_WINDOWS */
7985 PyObject *result;
7986 DWORD sig = (DWORD)signal;
7987 DWORD err;
7988 HANDLE handle;
7989
7990 /* Console processes which share a common console can be sent CTRL+C or
7991 CTRL+BREAK events, provided they handle said events. */
7992 if (sig == CTRL_C_EVENT || sig == CTRL_BREAK_EVENT) {
7993 if (GenerateConsoleCtrlEvent(sig, (DWORD)pid) == 0) {
7994 err = GetLastError();
7995 PyErr_SetFromWindowsErr(err);
7996 }
7997 else
7998 Py_RETURN_NONE;
7999 }
8000
8001 /* If the signal is outside of what GenerateConsoleCtrlEvent can use,
8002 attempt to open and terminate the process. */
8003 handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, (DWORD)pid);
8004 if (handle == NULL) {
8005 err = GetLastError();
8006 return PyErr_SetFromWindowsErr(err);
8007 }
8008
8009 if (TerminateProcess(handle, sig) == 0) {
8010 err = GetLastError();
8011 result = PyErr_SetFromWindowsErr(err);
8012 } else {
8013 Py_INCREF(Py_None);
8014 result = Py_None;
8015 }
8016
8017 CloseHandle(handle);
8018 return result;
8019 #endif /* !MS_WINDOWS */
8020 }
8021 #endif /* HAVE_KILL */
8022
8023
8024 #ifdef HAVE_KILLPG
8025 /*[clinic input]
8026 os.killpg
8027
8028 pgid: pid_t
8029 signal: int
8030 /
8031
8032 Kill a process group with a signal.
8033 [clinic start generated code]*/
8034
8035 static PyObject *
8036 os_killpg_impl(PyObject *module, pid_t pgid, int signal)
8037 /*[clinic end generated code: output=6dbcd2f1fdf5fdba input=38b5449eb8faec19]*/
8038 {
8039 if (PySys_Audit("os.killpg", "ii", pgid, signal) < 0) {
8040 return NULL;
8041 }
8042 /* XXX some man pages make the `pgid` parameter an int, others
8043 a pid_t. Since getpgrp() returns a pid_t, we assume killpg should
8044 take the same type. Moreover, pid_t is always at least as wide as
8045 int (else compilation of this module fails), which is safe. */
8046 if (killpg(pgid, signal) == -1)
8047 return posix_error();
8048 Py_RETURN_NONE;
8049 }
8050 #endif /* HAVE_KILLPG */
8051
8052
8053 #ifdef HAVE_PLOCK
8054 #ifdef HAVE_SYS_LOCK_H
8055 #include <sys/lock.h>
8056 #endif
8057
8058 /*[clinic input]
8059 os.plock
8060 op: int
8061 /
8062
8063 Lock program segments into memory.");
8064 [clinic start generated code]*/
8065
8066 static PyObject *
8067 os_plock_impl(PyObject *module, int op)
8068 /*[clinic end generated code: output=81424167033b168e input=e6e5e348e1525f60]*/
8069 {
8070 if (plock(op) == -1)
8071 return posix_error();
8072 Py_RETURN_NONE;
8073 }
8074 #endif /* HAVE_PLOCK */
8075
8076
8077 #ifdef HAVE_SETUID
8078 /*[clinic input]
8079 os.setuid
8080
8081 uid: uid_t
8082 /
8083
8084 Set the current process's user id.
8085 [clinic start generated code]*/
8086
8087 static PyObject *
8088 os_setuid_impl(PyObject *module, uid_t uid)
8089 /*[clinic end generated code: output=a0a41fd0d1ec555f input=c921a3285aa22256]*/
8090 {
8091 if (setuid(uid) < 0)
8092 return posix_error();
8093 Py_RETURN_NONE;
8094 }
8095 #endif /* HAVE_SETUID */
8096
8097
8098 #ifdef HAVE_SETEUID
8099 /*[clinic input]
8100 os.seteuid
8101
8102 euid: uid_t
8103 /
8104
8105 Set the current process's effective user id.
8106 [clinic start generated code]*/
8107
8108 static PyObject *
8109 os_seteuid_impl(PyObject *module, uid_t euid)
8110 /*[clinic end generated code: output=102e3ad98361519a input=ba93d927e4781aa9]*/
8111 {
8112 if (seteuid(euid) < 0)
8113 return posix_error();
8114 Py_RETURN_NONE;
8115 }
8116 #endif /* HAVE_SETEUID */
8117
8118
8119 #ifdef HAVE_SETEGID
8120 /*[clinic input]
8121 os.setegid
8122
8123 egid: gid_t
8124 /
8125
8126 Set the current process's effective group id.
8127 [clinic start generated code]*/
8128
8129 static PyObject *
8130 os_setegid_impl(PyObject *module, gid_t egid)
8131 /*[clinic end generated code: output=4e4b825a6a10258d input=4080526d0ccd6ce3]*/
8132 {
8133 if (setegid(egid) < 0)
8134 return posix_error();
8135 Py_RETURN_NONE;
8136 }
8137 #endif /* HAVE_SETEGID */
8138
8139
8140 #ifdef HAVE_SETREUID
8141 /*[clinic input]
8142 os.setreuid
8143
8144 ruid: uid_t
8145 euid: uid_t
8146 /
8147
8148 Set the current process's real and effective user ids.
8149 [clinic start generated code]*/
8150
8151 static PyObject *
8152 os_setreuid_impl(PyObject *module, uid_t ruid, uid_t euid)
8153 /*[clinic end generated code: output=62d991210006530a input=0ca8978de663880c]*/
8154 {
8155 if (setreuid(ruid, euid) < 0) {
8156 return posix_error();
8157 } else {
8158 Py_RETURN_NONE;
8159 }
8160 }
8161 #endif /* HAVE_SETREUID */
8162
8163
8164 #ifdef HAVE_SETREGID
8165 /*[clinic input]
8166 os.setregid
8167
8168 rgid: gid_t
8169 egid: gid_t
8170 /
8171
8172 Set the current process's real and effective group ids.
8173 [clinic start generated code]*/
8174
8175 static PyObject *
8176 os_setregid_impl(PyObject *module, gid_t rgid, gid_t egid)
8177 /*[clinic end generated code: output=aa803835cf5342f3 input=c59499f72846db78]*/
8178 {
8179 if (setregid(rgid, egid) < 0)
8180 return posix_error();
8181 Py_RETURN_NONE;
8182 }
8183 #endif /* HAVE_SETREGID */
8184
8185
8186 #ifdef HAVE_SETGID
8187 /*[clinic input]
8188 os.setgid
8189 gid: gid_t
8190 /
8191
8192 Set the current process's group id.
8193 [clinic start generated code]*/
8194
8195 static PyObject *
8196 os_setgid_impl(PyObject *module, gid_t gid)
8197 /*[clinic end generated code: output=bdccd7403f6ad8c3 input=27d30c4059045dc6]*/
8198 {
8199 if (setgid(gid) < 0)
8200 return posix_error();
8201 Py_RETURN_NONE;
8202 }
8203 #endif /* HAVE_SETGID */
8204
8205
8206 #ifdef HAVE_SETGROUPS
8207 /*[clinic input]
8208 os.setgroups
8209
8210 groups: object
8211 /
8212
8213 Set the groups of the current process to list.
8214 [clinic start generated code]*/
8215
8216 static PyObject *
8217 os_setgroups(PyObject *module, PyObject *groups)
8218 /*[clinic end generated code: output=3fcb32aad58c5ecd input=fa742ca3daf85a7e]*/
8219 {
8220 if (!PySequence_Check(groups)) {
8221 PyErr_SetString(PyExc_TypeError, "setgroups argument must be a sequence");
8222 return NULL;
8223 }
8224 Py_ssize_t len = PySequence_Size(groups);
8225 if (len < 0) {
8226 return NULL;
8227 }
8228 if (len > MAX_GROUPS) {
8229 PyErr_SetString(PyExc_ValueError, "too many groups");
8230 return NULL;
8231 }
8232
8233 gid_t *grouplist = PyMem_New(gid_t, len);
8234 for (Py_ssize_t i = 0; i < len; i++) {
8235 PyObject *elem;
8236 elem = PySequence_GetItem(groups, i);
8237 if (!elem) {
8238 PyMem_Free(grouplist);
8239 return NULL;
8240 }
8241 if (!PyLong_Check(elem)) {
8242 PyErr_SetString(PyExc_TypeError,
8243 "groups must be integers");
8244 Py_DECREF(elem);
8245 PyMem_Free(grouplist);
8246 return NULL;
8247 } else {
8248 if (!_Py_Gid_Converter(elem, &grouplist[i])) {
8249 Py_DECREF(elem);
8250 PyMem_Free(grouplist);
8251 return NULL;
8252 }
8253 }
8254 Py_DECREF(elem);
8255 }
8256
8257 if (setgroups(len, grouplist) < 0) {
8258 PyMem_Free(grouplist);
8259 return posix_error();
8260 }
8261 PyMem_Free(grouplist);
8262 Py_RETURN_NONE;
8263 }
8264 #endif /* HAVE_SETGROUPS */
8265
8266 #if defined(HAVE_WAIT3) || defined(HAVE_WAIT4)
8267 static PyObject *
8268 wait_helper(PyObject *module, pid_t pid, int status, struct rusage *ru)
8269 {
8270 PyObject *result;
8271 PyObject *struct_rusage;
8272
8273 if (pid == -1)
8274 return posix_error();
8275
8276 // If wait succeeded but no child was ready to report status, ru will not
8277 // have been populated.
8278 if (pid == 0) {
8279 memset(ru, 0, sizeof(*ru));
8280 }
8281
8282 struct_rusage = _PyImport_GetModuleAttrString("resource", "struct_rusage");
8283 if (struct_rusage == NULL)
8284 return NULL;
8285
8286 /* XXX(nnorwitz): Copied (w/mods) from resource.c, there should be only one. */
8287 result = PyStructSequence_New((PyTypeObject*) struct_rusage);
8288 Py_DECREF(struct_rusage);
8289 if (!result)
8290 return NULL;
8291
8292 #ifndef doubletime
8293 #define doubletime(TV) ((double)(TV).tv_sec + (TV).tv_usec * 0.000001)
8294 #endif
8295
8296 PyStructSequence_SET_ITEM(result, 0,
8297 PyFloat_FromDouble(doubletime(ru->ru_utime)));
8298 PyStructSequence_SET_ITEM(result, 1,
8299 PyFloat_FromDouble(doubletime(ru->ru_stime)));
8300 #define SET_INT(result, index, value)\
8301 PyStructSequence_SET_ITEM(result, index, PyLong_FromLong(value))
8302 SET_INT(result, 2, ru->ru_maxrss);
8303 SET_INT(result, 3, ru->ru_ixrss);
8304 SET_INT(result, 4, ru->ru_idrss);
8305 SET_INT(result, 5, ru->ru_isrss);
8306 SET_INT(result, 6, ru->ru_minflt);
8307 SET_INT(result, 7, ru->ru_majflt);
8308 SET_INT(result, 8, ru->ru_nswap);
8309 SET_INT(result, 9, ru->ru_inblock);
8310 SET_INT(result, 10, ru->ru_oublock);
8311 SET_INT(result, 11, ru->ru_msgsnd);
8312 SET_INT(result, 12, ru->ru_msgrcv);
8313 SET_INT(result, 13, ru->ru_nsignals);
8314 SET_INT(result, 14, ru->ru_nvcsw);
8315 SET_INT(result, 15, ru->ru_nivcsw);
8316 #undef SET_INT
8317
8318 if (PyErr_Occurred()) {
8319 Py_DECREF(result);
8320 return NULL;
8321 }
8322
8323 return Py_BuildValue("NiN", PyLong_FromPid(pid), status, result);
8324 }
8325 #endif /* HAVE_WAIT3 || HAVE_WAIT4 */
8326
8327
8328 #ifdef HAVE_WAIT3
8329 /*[clinic input]
8330 os.wait3
8331
8332 options: int
8333 Wait for completion of a child process.
8334
8335 Returns a tuple of information about the child process:
8336 (pid, status, rusage)
8337 [clinic start generated code]*/
8338
8339 static PyObject *
8340 os_wait3_impl(PyObject *module, int options)
8341 /*[clinic end generated code: output=92c3224e6f28217a input=8ac4c56956b61710]*/
8342 {
8343 pid_t pid;
8344 struct rusage ru;
8345 int async_err = 0;
8346 WAIT_TYPE status;
8347 WAIT_STATUS_INT(status) = 0;
8348
8349 do {
8350 Py_BEGIN_ALLOW_THREADS
8351 pid = wait3(&status, options, &ru);
8352 Py_END_ALLOW_THREADS
8353 } while (pid < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
8354 if (pid < 0)
8355 return (!async_err) ? posix_error() : NULL;
8356
8357 return wait_helper(module, pid, WAIT_STATUS_INT(status), &ru);
8358 }
8359 #endif /* HAVE_WAIT3 */
8360
8361
8362 #ifdef HAVE_WAIT4
8363 /*[clinic input]
8364
8365 os.wait4
8366
8367 pid: pid_t
8368 options: int
8369
8370 Wait for completion of a specific child process.
8371
8372 Returns a tuple of information about the child process:
8373 (pid, status, rusage)
8374 [clinic start generated code]*/
8375
8376 static PyObject *
8377 os_wait4_impl(PyObject *module, pid_t pid, int options)
8378 /*[clinic end generated code: output=66195aa507b35f70 input=d11deed0750600ba]*/
8379 {
8380 pid_t res;
8381 struct rusage ru;
8382 int async_err = 0;
8383 WAIT_TYPE status;
8384 WAIT_STATUS_INT(status) = 0;
8385
8386 do {
8387 Py_BEGIN_ALLOW_THREADS
8388 res = wait4(pid, &status, options, &ru);
8389 Py_END_ALLOW_THREADS
8390 } while (res < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
8391 if (res < 0)
8392 return (!async_err) ? posix_error() : NULL;
8393
8394 return wait_helper(module, res, WAIT_STATUS_INT(status), &ru);
8395 }
8396 #endif /* HAVE_WAIT4 */
8397
8398
8399 #if defined(HAVE_WAITID) && !defined(__APPLE__)
8400 /*[clinic input]
8401 os.waitid
8402
8403 idtype: idtype_t
8404 Must be one of be P_PID, P_PGID or P_ALL.
8405 id: id_t
8406 The id to wait on.
8407 options: int
8408 Constructed from the ORing of one or more of WEXITED, WSTOPPED
8409 or WCONTINUED and additionally may be ORed with WNOHANG or WNOWAIT.
8410 /
8411
8412 Returns the result of waiting for a process or processes.
8413
8414 Returns either waitid_result or None if WNOHANG is specified and there are
8415 no children in a waitable state.
8416 [clinic start generated code]*/
8417
8418 static PyObject *
8419 os_waitid_impl(PyObject *module, idtype_t idtype, id_t id, int options)
8420 /*[clinic end generated code: output=5d2e1c0bde61f4d8 input=d8e7f76e052b7920]*/
8421 {
8422 PyObject *result;
8423 int res;
8424 int async_err = 0;
8425 siginfo_t si;
8426 si.si_pid = 0;
8427
8428 do {
8429 Py_BEGIN_ALLOW_THREADS
8430 res = waitid(idtype, id, &si, options);
8431 Py_END_ALLOW_THREADS
8432 } while (res < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
8433 if (res < 0)
8434 return (!async_err) ? posix_error() : NULL;
8435
8436 if (si.si_pid == 0)
8437 Py_RETURN_NONE;
8438
8439 PyObject *WaitidResultType = get_posix_state(module)->WaitidResultType;
8440 result = PyStructSequence_New((PyTypeObject *)WaitidResultType);
8441 if (!result)
8442 return NULL;
8443
8444 PyStructSequence_SET_ITEM(result, 0, PyLong_FromPid(si.si_pid));
8445 PyStructSequence_SET_ITEM(result, 1, _PyLong_FromUid(si.si_uid));
8446 PyStructSequence_SET_ITEM(result, 2, PyLong_FromLong((long)(si.si_signo)));
8447 PyStructSequence_SET_ITEM(result, 3, PyLong_FromLong((long)(si.si_status)));
8448 PyStructSequence_SET_ITEM(result, 4, PyLong_FromLong((long)(si.si_code)));
8449 if (PyErr_Occurred()) {
8450 Py_DECREF(result);
8451 return NULL;
8452 }
8453
8454 return result;
8455 }
8456 #endif /* defined(HAVE_WAITID) && !defined(__APPLE__) */
8457
8458
8459 #if defined(HAVE_WAITPID)
8460 /*[clinic input]
8461 os.waitpid
8462 pid: pid_t
8463 options: int
8464 /
8465
8466 Wait for completion of a given child process.
8467
8468 Returns a tuple of information regarding the child process:
8469 (pid, status)
8470
8471 The options argument is ignored on Windows.
8472 [clinic start generated code]*/
8473
8474 static PyObject *
8475 6712 os_waitpid_impl(PyObject *module, pid_t pid, int options)
8476 /*[clinic end generated code: output=5c37c06887a20270 input=0bf1666b8758fda3]*/
8477 {
8478 pid_t res;
8479 6712 int async_err = 0;
8480 WAIT_TYPE status;
8481 6712 WAIT_STATUS_INT(status) = 0;
8482
8483 do {
8484 6712 Py_BEGIN_ALLOW_THREADS
8485 6712 res = waitpid(pid, &status, options);
8486 6712 Py_END_ALLOW_THREADS
8487
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 6712 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
6712 } while (res < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
8488
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6712 times.
6712 if (res < 0)
8489 return (!async_err) ? posix_error() : NULL;
8490
8491 6712 return Py_BuildValue("Ni", PyLong_FromPid(res), WAIT_STATUS_INT(status));
8492 }
8493 #elif defined(HAVE_CWAIT)
8494 /* MS C has a variant of waitpid() that's usable for most purposes. */
8495 /*[clinic input]
8496 os.waitpid
8497 pid: intptr_t
8498 options: int
8499 /
8500
8501 Wait for completion of a given process.
8502
8503 Returns a tuple of information regarding the process:
8504 (pid, status << 8)
8505
8506 The options argument is ignored on Windows.
8507 [clinic start generated code]*/
8508
8509 static PyObject *
8510 os_waitpid_impl(PyObject *module, intptr_t pid, int options)
8511 /*[clinic end generated code: output=be836b221271d538 input=40f2440c515410f8]*/
8512 {
8513 int status;
8514 intptr_t res;
8515 int async_err = 0;
8516
8517 do {
8518 Py_BEGIN_ALLOW_THREADS
8519 _Py_BEGIN_SUPPRESS_IPH
8520 res = _cwait(&status, pid, options);
8521 _Py_END_SUPPRESS_IPH
8522 Py_END_ALLOW_THREADS
8523 } while (res < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
8524 if (res < 0)
8525 return (!async_err) ? posix_error() : NULL;
8526
8527 unsigned long long ustatus = (unsigned int)status;
8528
8529 /* shift the status left a byte so this is more like the POSIX waitpid */
8530 return Py_BuildValue(_Py_PARSE_INTPTR "K", res, ustatus << 8);
8531 }
8532 #endif
8533
8534
8535 #ifdef HAVE_WAIT
8536 /*[clinic input]
8537 os.wait
8538
8539 Wait for completion of a child process.
8540
8541 Returns a tuple of information about the child process:
8542 (pid, status)
8543 [clinic start generated code]*/
8544
8545 static PyObject *
8546 os_wait_impl(PyObject *module)
8547 /*[clinic end generated code: output=6bc419ac32fb364b input=03b0182d4a4700ce]*/
8548 {
8549 pid_t pid;
8550 int async_err = 0;
8551 WAIT_TYPE status;
8552 WAIT_STATUS_INT(status) = 0;
8553
8554 do {
8555 Py_BEGIN_ALLOW_THREADS
8556 pid = wait(&status);
8557 Py_END_ALLOW_THREADS
8558 } while (pid < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
8559 if (pid < 0)
8560 return (!async_err) ? posix_error() : NULL;
8561
8562 return Py_BuildValue("Ni", PyLong_FromPid(pid), WAIT_STATUS_INT(status));
8563 }
8564 #endif /* HAVE_WAIT */
8565
8566 #if defined(__linux__) && defined(__NR_pidfd_open)
8567 /*[clinic input]
8568 os.pidfd_open
8569 pid: pid_t
8570 flags: unsigned_int = 0
8571
8572 Return a file descriptor referring to the process *pid*.
8573
8574 The descriptor can be used to perform process management without races and
8575 signals.
8576 [clinic start generated code]*/
8577
8578 static PyObject *
8579 os_pidfd_open_impl(PyObject *module, pid_t pid, unsigned int flags)
8580 /*[clinic end generated code: output=5c7252698947dc41 input=c3fd99ce947ccfef]*/
8581 {
8582 int fd = syscall(__NR_pidfd_open, pid, flags);
8583 if (fd < 0) {
8584 return posix_error();
8585 }
8586 return PyLong_FromLong(fd);
8587 }
8588 #endif
8589
8590
8591 #if defined(HAVE_READLINK) || defined(MS_WINDOWS)
8592 /*[clinic input]
8593 os.readlink
8594
8595 path: path_t
8596 *
8597 dir_fd: dir_fd(requires='readlinkat') = None
8598
8599 Return a string representing the path to which the symbolic link points.
8600
8601 If dir_fd is not None, it should be a file descriptor open to a directory,
8602 and path should be relative; path will then be relative to that directory.
8603
8604 dir_fd may not be implemented on your platform. If it is unavailable,
8605 using it will raise a NotImplementedError.
8606 [clinic start generated code]*/
8607
8608 static PyObject *
8609 3152 os_readlink_impl(PyObject *module, path_t *path, int dir_fd)
8610 /*[clinic end generated code: output=d21b732a2e814030 input=113c87e0db1ecaf2]*/
8611 {
8612 #if defined(HAVE_READLINK)
8613 char buffer[MAXPATHLEN+1];
8614 ssize_t length;
8615 #ifdef HAVE_READLINKAT
8616 3152 int readlinkat_unavailable = 0;
8617 #endif
8618
8619 3152 Py_BEGIN_ALLOW_THREADS
8620 #ifdef HAVE_READLINKAT
8621
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3152 times.
3152 if (dir_fd != DEFAULT_DIR_FD) {
8622 if (HAVE_READLINKAT_RUNTIME) {
8623 length = readlinkat(dir_fd, path->narrow, buffer, MAXPATHLEN);
8624 } else {
8625 readlinkat_unavailable = 1;
8626 }
8627 } else
8628 #endif
8629 3152 length = readlink(path->narrow, buffer, MAXPATHLEN);
8630 3152 Py_END_ALLOW_THREADS
8631
8632 #ifdef HAVE_READLINKAT
8633
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3152 times.
3152 if (readlinkat_unavailable) {
8634 argument_unavailable_error(NULL, "dir_fd");
8635 return NULL;
8636 }
8637 #endif
8638
8639
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3152 times.
3152 if (length < 0) {
8640 return path_error(path);
8641 }
8642 3152 buffer[length] = '\0';
8643
8644
1/2
✓ Branch 2 taken 3152 times.
✗ Branch 3 not taken.
3152 if (PyUnicode_Check(path->object))
8645 3152 return PyUnicode_DecodeFSDefaultAndSize(buffer, length);
8646 else
8647 return PyBytes_FromStringAndSize(buffer, length);
8648 #elif defined(MS_WINDOWS)
8649 DWORD n_bytes_returned;
8650 DWORD io_result = 0;
8651 HANDLE reparse_point_handle;
8652 char target_buffer[_Py_MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
8653 _Py_REPARSE_DATA_BUFFER *rdb = (_Py_REPARSE_DATA_BUFFER *)target_buffer;
8654 PyObject *result = NULL;
8655
8656 /* First get a handle to the reparse point */
8657 Py_BEGIN_ALLOW_THREADS
8658 reparse_point_handle = CreateFileW(
8659 path->wide,
8660 0,
8661 0,
8662 0,
8663 OPEN_EXISTING,
8664 FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS,
8665 0);
8666 if (reparse_point_handle != INVALID_HANDLE_VALUE) {
8667 /* New call DeviceIoControl to read the reparse point */
8668 io_result = DeviceIoControl(
8669 reparse_point_handle,
8670 FSCTL_GET_REPARSE_POINT,
8671 0, 0, /* in buffer */
8672 target_buffer, sizeof(target_buffer),
8673 &n_bytes_returned,
8674 0 /* we're not using OVERLAPPED_IO */
8675 );
8676 CloseHandle(reparse_point_handle);
8677 }
8678 Py_END_ALLOW_THREADS
8679
8680 if (io_result == 0) {
8681 return path_error(path);
8682 }
8683
8684 wchar_t *name = NULL;
8685 Py_ssize_t nameLen = 0;
8686 if (rdb->ReparseTag == IO_REPARSE_TAG_SYMLINK)
8687 {
8688 name = (wchar_t *)((char*)rdb->SymbolicLinkReparseBuffer.PathBuffer +
8689 rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset);
8690 nameLen = rdb->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(wchar_t);
8691 }
8692 else if (rdb->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT)
8693 {
8694 name = (wchar_t *)((char*)rdb->MountPointReparseBuffer.PathBuffer +
8695 rdb->MountPointReparseBuffer.SubstituteNameOffset);
8696 nameLen = rdb->MountPointReparseBuffer.SubstituteNameLength / sizeof(wchar_t);
8697 }
8698 else
8699 {
8700 PyErr_SetString(PyExc_ValueError, "not a symbolic link");
8701 }
8702 if (name) {
8703 if (nameLen > 4 && wcsncmp(name, L"\\??\\", 4) == 0) {
8704 /* Our buffer is mutable, so this is okay */
8705 name[1] = L'\\';
8706 }
8707 result = PyUnicode_FromWideChar(name, nameLen);
8708 if (result && path->narrow) {
8709 Py_SETREF(result, PyUnicode_EncodeFSDefault(result));
8710 }
8711 }
8712 return result;
8713 #endif
8714 }
8715 #endif /* defined(HAVE_READLINK) || defined(MS_WINDOWS) */
8716
8717 #if defined(MS_WINDOWS)
8718
8719 /* Remove the last portion of the path - return 0 on success */
8720 static int
8721 _dirnameW(WCHAR *path)
8722 {
8723 WCHAR *ptr;
8724 size_t length = wcsnlen_s(path, MAX_PATH);
8725 if (length == MAX_PATH) {
8726 return -1;
8727 }
8728
8729 /* walk the path from the end until a backslash is encountered */
8730 for(ptr = path + length; ptr != path; ptr--) {
8731 if (*ptr == L'\\' || *ptr == L'/') {
8732 break;
8733 }
8734 }
8735 *ptr = 0;
8736 return 0;
8737 }
8738
8739 #endif
8740
8741 #ifdef HAVE_SYMLINK
8742
8743 #if defined(MS_WINDOWS)
8744
8745 /* Is this path absolute? */
8746 static int
8747 _is_absW(const WCHAR *path)
8748 {
8749 return path[0] == L'\\' || path[0] == L'/' ||
8750 (path[0] && path[1] == L':');
8751 }
8752
8753 /* join root and rest with a backslash - return 0 on success */
8754 static int
8755 _joinW(WCHAR *dest_path, const WCHAR *root, const WCHAR *rest)
8756 {
8757 if (_is_absW(rest)) {
8758 return wcscpy_s(dest_path, MAX_PATH, rest);
8759 }
8760
8761 if (wcscpy_s(dest_path, MAX_PATH, root)) {
8762 return -1;
8763 }
8764
8765 if (dest_path[0] && wcscat_s(dest_path, MAX_PATH, L"\\")) {
8766 return -1;
8767 }
8768
8769 return wcscat_s(dest_path, MAX_PATH, rest);
8770 }
8771
8772 /* Return True if the path at src relative to dest is a directory */
8773 static int
8774 _check_dirW(LPCWSTR src, LPCWSTR dest)
8775 {
8776 WIN32_FILE_ATTRIBUTE_DATA src_info;
8777 WCHAR dest_parent[MAX_PATH];
8778 WCHAR src_resolved[MAX_PATH] = L"";
8779
8780 /* dest_parent = os.path.dirname(dest) */
8781 if (wcscpy_s(dest_parent, MAX_PATH, dest) ||
8782 _dirnameW(dest_parent)) {
8783 return 0;
8784 }
8785 /* src_resolved = os.path.join(dest_parent, src) */
8786 if (_joinW(src_resolved, dest_parent, src)) {
8787 return 0;
8788 }
8789 return (
8790 GetFileAttributesExW(src_resolved, GetFileExInfoStandard, &src_info)
8791 && src_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY
8792 );
8793 }
8794 #endif
8795
8796
8797 /*[clinic input]
8798 os.symlink
8799 src: path_t
8800 dst: path_t
8801 target_is_directory: bool = False
8802 *
8803 dir_fd: dir_fd(requires='symlinkat')=None
8804
8805 # "symlink(src, dst, target_is_directory=False, *, dir_fd=None)\n\n\
8806
8807 Create a symbolic link pointing to src named dst.
8808
8809 target_is_directory is required on Windows if the target is to be
8810 interpreted as a directory. (On Windows, symlink requires
8811 Windows 6.0 or greater, and raises a NotImplementedError otherwise.)
8812 target_is_directory is ignored on non-Windows platforms.
8813
8814 If dir_fd is not None, it should be a file descriptor open to a directory,
8815 and path should be relative; path will then be relative to that directory.
8816 dir_fd may not be implemented on your platform.
8817 If it is unavailable, using it will raise a NotImplementedError.
8818
8819 [clinic start generated code]*/
8820
8821 static PyObject *
8822 4 os_symlink_impl(PyObject *module, path_t *src, path_t *dst,
8823 int target_is_directory, int dir_fd)
8824 /*[clinic end generated code: output=08ca9f3f3cf960f6 input=e820ec4472547bc3]*/
8825 {
8826 #ifdef MS_WINDOWS
8827 DWORD result;
8828 DWORD flags = 0;
8829
8830 /* Assumed true, set to false if detected to not be available. */
8831 static int windows_has_symlink_unprivileged_flag = TRUE;
8832 #else
8833 int result;
8834 #ifdef HAVE_SYMLINKAT
8835 4 int symlinkat_unavailable = 0;
8836 #endif
8837 #endif
8838
8839
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
4 if (PySys_Audit("os.symlink", "OOi", src->object, dst->object,
8840 dir_fd == DEFAULT_DIR_FD ? -1 : dir_fd) < 0) {
8841 return NULL;
8842 }
8843
8844 #ifdef MS_WINDOWS
8845
8846 if (windows_has_symlink_unprivileged_flag) {
8847 /* Allow non-admin symlinks if system allows it. */
8848 flags |= SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
8849 }
8850
8851 Py_BEGIN_ALLOW_THREADS
8852 _Py_BEGIN_SUPPRESS_IPH
8853 /* if src is a directory, ensure flags==1 (target_is_directory bit) */
8854 if (target_is_directory || _check_dirW(src->wide, dst->wide)) {
8855 flags |= SYMBOLIC_LINK_FLAG_DIRECTORY;
8856 }
8857
8858 result = CreateSymbolicLinkW(dst->wide, src->wide, flags);
8859 _Py_END_SUPPRESS_IPH
8860 Py_END_ALLOW_THREADS
8861
8862 if (windows_has_symlink_unprivileged_flag && !result &&
8863 ERROR_INVALID_PARAMETER == GetLastError()) {
8864
8865 Py_BEGIN_ALLOW_THREADS
8866 _Py_BEGIN_SUPPRESS_IPH
8867 /* This error might be caused by
8868 SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE not being supported.
8869 Try again, and update windows_has_symlink_unprivileged_flag if we
8870 are successful this time.
8871
8872 NOTE: There is a risk of a race condition here if there are other
8873 conditions than the flag causing ERROR_INVALID_PARAMETER, and
8874 another process (or thread) changes that condition in between our
8875 calls to CreateSymbolicLink.
8876 */
8877 flags &= ~(SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE);
8878 result = CreateSymbolicLinkW(dst->wide, src->wide, flags);
8879 _Py_END_SUPPRESS_IPH
8880 Py_END_ALLOW_THREADS
8881
8882 if (result || ERROR_INVALID_PARAMETER != GetLastError()) {
8883 windows_has_symlink_unprivileged_flag = FALSE;
8884 }
8885 }
8886
8887 if (!result)
8888 return path_error2(src, dst);
8889
8890 #else
8891
8892
3/8
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
4 if ((src->narrow && dst->wide) || (src->wide && dst->narrow)) {
8893 PyErr_SetString(PyExc_ValueError,
8894 "symlink: src and dst must be the same type");
8895 return NULL;
8896 }
8897
8898 4 Py_BEGIN_ALLOW_THREADS
8899 #ifdef HAVE_SYMLINKAT
8900
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (dir_fd != DEFAULT_DIR_FD) {
8901 if (HAVE_SYMLINKAT_RUNTIME) {
8902 result = symlinkat(src->narrow, dir_fd, dst->narrow);
8903 } else {
8904 symlinkat_unavailable = 1;
8905 }
8906 } else
8907 #endif
8908 4 result = symlink(src->narrow, dst->narrow);
8909 4 Py_END_ALLOW_THREADS
8910
8911 #ifdef HAVE_SYMLINKAT
8912
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (symlinkat_unavailable) {
8913 argument_unavailable_error(NULL, "dir_fd");
8914 return NULL;
8915 }
8916 #endif
8917
8918
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (result)
8919 return path_error2(src, dst);
8920 #endif
8921
8922 4 Py_RETURN_NONE;
8923 }
8924 #endif /* HAVE_SYMLINK */
8925
8926
8927
8928
8929 static PyStructSequence_Field times_result_fields[] = {
8930 {"user", "user time"},
8931 {"system", "system time"},
8932 {"children_user", "user time of children"},
8933 {"children_system", "system time of children"},
8934 {"elapsed", "elapsed time since an arbitrary point in the past"},
8935 {NULL}
8936 };
8937
8938 PyDoc_STRVAR(times_result__doc__,
8939 "times_result: Result from os.times().\n\n\
8940 This object may be accessed either as a tuple of\n\
8941 (user, system, children_user, children_system, elapsed),\n\
8942 or via the attributes user, system, children_user, children_system,\n\
8943 and elapsed.\n\
8944 \n\
8945 See os.times for more information.");
8946
8947 static PyStructSequence_Desc times_result_desc = {
8948 "times_result", /* name */
8949 times_result__doc__, /* doc */
8950 times_result_fields,
8951 5
8952 };
8953
8954 #ifdef MS_WINDOWS
8955 #define HAVE_TIMES /* mandatory, for the method table */
8956 #endif
8957
8958 #ifdef HAVE_TIMES
8959
8960 static PyObject *
8961 build_times_result(PyObject *module, double user, double system,
8962 double children_user, double children_system,
8963 double elapsed)
8964 {
8965 PyObject *TimesResultType = get_posix_state(module)->TimesResultType;
8966 PyObject *value = PyStructSequence_New((PyTypeObject *)TimesResultType);
8967 if (value == NULL)
8968 return NULL;
8969
8970 #define SET(i, field) \
8971 { \
8972 PyObject *o = PyFloat_FromDouble(field); \
8973 if (!o) { \
8974 Py_DECREF(value); \
8975 return NULL; \
8976 } \
8977 PyStructSequence_SET_ITEM(value, i, o); \
8978 } \
8979
8980 SET(0, user);
8981 SET(1, system);
8982 SET(2, children_user);
8983 SET(3, children_system);
8984 SET(4, elapsed);
8985
8986 #undef SET
8987
8988 return value;
8989 }
8990
8991
8992 #ifndef MS_WINDOWS
8993 #define NEED_TICKS_PER_SECOND
8994 static long ticks_per_second = -1;
8995 #endif /* MS_WINDOWS */
8996
8997 /*[clinic input]
8998 os.times
8999
9000 Return a collection containing process timing information.
9001
9002 The object returned behaves like a named tuple with these fields:
9003 (utime, stime, cutime, cstime, elapsed_time)
9004 All fields are floating point numbers.
9005 [clinic start generated code]*/
9006
9007 static PyObject *
9008 os_times_impl(PyObject *module)
9009 /*[clinic end generated code: output=35f640503557d32a input=2bf9df3d6ab2e48b]*/
9010 #ifdef MS_WINDOWS
9011 {
9012 FILETIME create, exit, kernel, user;
9013 HANDLE hProc;
9014 hProc = GetCurrentProcess();
9015 GetProcessTimes(hProc, &create, &exit, &kernel, &user);
9016 /* The fields of a FILETIME structure are the hi and lo part
9017 of a 64-bit value expressed in 100 nanosecond units.
9018 1e7 is one second in such units; 1e-7 the inverse.
9019 429.4967296 is 2**32 / 1e7 or 2**32 * 1e-7.
9020 */
9021 return build_times_result(module,
9022 (double)(user.dwHighDateTime*429.4967296 +
9023 user.dwLowDateTime*1e-7),
9024 (double)(kernel.dwHighDateTime*429.4967296 +
9025 kernel.dwLowDateTime*1e-7),
9026 (double)0,
9027 (double)0,
9028 (double)0);
9029 }
9030 #else /* MS_WINDOWS */
9031 {
9032
9033
9034 struct tms t;
9035 clock_t c;
9036 errno = 0;
9037 c = times(&t);
9038 if (c == (clock_t) -1)
9039 return posix_error();
9040 return build_times_result(module,
9041 (double)t.tms_utime / ticks_per_second,
9042 (double)t.tms_stime / ticks_per_second,
9043 (double)t.tms_cutime / ticks_per_second,
9044 (double)t.tms_cstime / ticks_per_second,
9045 (double)c / ticks_per_second);
9046 }
9047 #endif /* MS_WINDOWS */
9048 #endif /* HAVE_TIMES */
9049
9050
9051 #ifdef HAVE_GETSID
9052 /*[clinic input]
9053 os.getsid
9054
9055 pid: pid_t
9056 /
9057
9058 Call the system call getsid(pid) and return the result.
9059 [clinic start generated code]*/
9060
9061 static PyObject *
9062 os_getsid_impl(PyObject *module, pid_t pid)
9063 /*[clinic end generated code: output=112deae56b306460 input=eeb2b923a30ce04e]*/
9064 {
9065 int sid;
9066 sid = getsid(pid);
9067 if (sid < 0)
9068 return posix_error();
9069 return PyLong_FromLong((long)sid);
9070 }
9071 #endif /* HAVE_GETSID */
9072
9073
9074 #ifdef HAVE_SETSID
9075 /*[clinic input]
9076 os.setsid
9077
9078 Call the system call setsid().
9079 [clinic start generated code]*/
9080
9081 static PyObject *
9082 os_setsid_impl(PyObject *module)
9083 /*[clinic end generated code: output=e2ddedd517086d77 input=5fff45858e2f0776]*/
9084 {
9085 if (setsid() < 0)
9086 return posix_error();
9087 Py_RETURN_NONE;
9088 }
9089 #endif /* HAVE_SETSID */
9090
9091
9092 #ifdef HAVE_SETPGID
9093 /*[clinic input]
9094 os.setpgid
9095
9096 pid: pid_t
9097 pgrp: pid_t
9098 /
9099
9100 Call the system call setpgid(pid, pgrp).
9101 [clinic start generated code]*/
9102
9103 static PyObject *
9104 os_setpgid_impl(PyObject *module, pid_t pid, pid_t pgrp)
9105 /*[clinic end generated code: output=6461160319a43d6a input=fceb395eca572e1a]*/
9106 {
9107 if (setpgid(pid, pgrp) < 0)
9108 return posix_error();
9109 Py_RETURN_NONE;
9110 }
9111 #endif /* HAVE_SETPGID */
9112
9113
9114 #ifdef HAVE_TCGETPGRP
9115 /*[clinic input]
9116 os.tcgetpgrp
9117
9118 fd: int
9119 /
9120
9121 Return the process group associated with the terminal specified by fd.
9122 [clinic start generated code]*/
9123
9124 static PyObject *
9125 os_tcgetpgrp_impl(PyObject *module, int fd)
9126 /*[clinic end generated code: output=f865e88be86c272b input=7f6c18eac10ada86]*/
9127 {
9128 pid_t pgid = tcgetpgrp(fd);
9129 if (pgid < 0)
9130 return posix_error();
9131 return PyLong_FromPid(pgid);
9132 }
9133 #endif /* HAVE_TCGETPGRP */
9134
9135
9136 #ifdef HAVE_TCSETPGRP
9137 /*[clinic input]
9138 os.tcsetpgrp
9139
9140 fd: int
9141 pgid: pid_t
9142 /
9143
9144 Set the process group associated with the terminal specified by fd.
9145 [clinic start generated code]*/
9146
9147 static PyObject *
9148 os_tcsetpgrp_impl(PyObject *module, int fd, pid_t pgid)
9149 /*[clinic end generated code: output=f1821a381b9daa39 input=5bdc997c6a619020]*/
9150 {
9151 if (tcsetpgrp(fd, pgid) < 0)
9152 return posix_error();
9153 Py_RETURN_NONE;
9154 }
9155 #endif /* HAVE_TCSETPGRP */
9156
9157 /* Functions acting on file descriptors */
9158
9159 #ifdef O_CLOEXEC
9160 extern int _Py_open_cloexec_works;
9161 #endif
9162
9163
9164 /*[clinic input]
9165 os.open -> int
9166 path: path_t
9167 flags: int
9168 mode: int = 0o777
9169 *
9170 dir_fd: dir_fd(requires='openat') = None
9171
9172 # "open(path, flags, mode=0o777, *, dir_fd=None)\n\n\
9173
9174 Open a file for low level IO. Returns a file descriptor (integer).
9175
9176 If dir_fd is not None, it should be a file descriptor open to a directory,
9177 and path should be relative; path will then be relative to that directory.
9178 dir_fd may not be implemented on your platform.
9179 If it is unavailable, using it will raise a NotImplementedError.
9180 [clinic start generated code]*/
9181
9182 static int
9183 10276 os_open_impl(PyObject *module, path_t *path, int flags, int mode, int dir_fd)
9184 /*[clinic end generated code: output=abc7227888c8bc73 input=ad8623b29acd2934]*/
9185 {
9186 int fd;
9187 10276 int async_err = 0;
9188 #ifdef HAVE_OPENAT
9189 10276 int openat_unavailable = 0;
9190 #endif
9191
9192 #ifdef O_CLOEXEC
9193 10276 int *atomic_flag_works = &_Py_open_cloexec_works;
9194 #elif !defined(MS_WINDOWS)
9195 int *atomic_flag_works = NULL;
9196 #endif
9197
9198 #ifdef MS_WINDOWS
9199 flags |= O_NOINHERIT;
9200 #elif defined(O_CLOEXEC)
9201 10276 flags |= O_CLOEXEC;
9202 #endif
9203
9204
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 10276 times.
10276 if (PySys_Audit("open", "OOi", path->object, Py_None, flags) < 0) {
9205 return -1;
9206 }
9207
9208 _Py_BEGIN_SUPPRESS_IPH
9209 do {
9210 10276 Py_BEGIN_ALLOW_THREADS
9211 #ifdef MS_WINDOWS
9212 fd = _wopen(path->wide, flags, mode);
9213 #else
9214 #ifdef HAVE_OPENAT
9215
2/2
✓ Branch 0 taken 712 times.
✓ Branch 1 taken 9564 times.
10276 if (dir_fd != DEFAULT_DIR_FD) {
9216 if (HAVE_OPENAT_RUNTIME) {
9217 712 fd = openat(dir_fd, path->narrow, flags, mode);
9218
9219 } else {
9220 openat_unavailable = 1;
9221 fd = -1;
9222 }
9223 } else
9224 #endif /* HAVE_OPENAT */
9225 9564 fd = open(path->narrow, flags, mode);
9226 #endif /* !MS_WINDOWS */
9227 10276 Py_END_ALLOW_THREADS
9228
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 10276 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
10276 } while (fd < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
9229 _Py_END_SUPPRESS_IPH
9230
9231 #ifdef HAVE_OPENAT
9232
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10276 times.
10276 if (openat_unavailable) {
9233 argument_unavailable_error(NULL, "dir_fd");
9234 return -1;
9235 }
9236 #endif
9237
9238
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10276 times.
10276 if (fd < 0) {
9239 if (!async_err)
9240 PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path->object);
9241 return -1;
9242 }
9243
9244 #ifndef MS_WINDOWS
9245
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 10276 times.
10276 if (_Py_set_inheritable(fd, 0, atomic_flag_works) < 0) {
9246 close(fd);
9247 return -1;
9248 }
9249 #endif
9250
9251 10276 return fd;
9252 }
9253
9254
9255 /*[clinic input]
9256 os.close
9257
9258 fd: int
9259
9260 Close a file descriptor.
9261 [clinic start generated code]*/
9262
9263 static PyObject *
9264 24399 os_close_impl(PyObject *module, int fd)
9265 /*[clinic end generated code: output=2fe4e93602822c14 input=2bc42451ca5c3223]*/
9266 {
9267 int res;
9268 /* We do not want to retry upon EINTR: see http://lwn.net/Articles/576478/
9269 * and http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
9270 * for more details.
9271 */
9272 24399 Py_BEGIN_ALLOW_THREADS
9273 _Py_BEGIN_SUPPRESS_IPH
9274 24399 res = close(fd);
9275 _Py_END_SUPPRESS_IPH
9276 24399 Py_END_ALLOW_THREADS
9277
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24399 times.
24399 if (res < 0)
9278 return posix_error();
9279 24399 Py_RETURN_NONE;
9280 }
9281
9282 /*[clinic input]
9283 os.closerange
9284
9285 fd_low: int
9286 fd_high: int
9287 /
9288
9289 Closes all file descriptors in [fd_low, fd_high), ignoring errors.
9290 [clinic start generated code]*/
9291
9292 static PyObject *
9293 os_closerange_impl(PyObject *module, int fd_low, int fd_high)
9294 /*[clinic end generated code: output=0ce5c20fcda681c2 input=5855a3d053ebd4ec]*/
9295 {
9296 Py_BEGIN_ALLOW_THREADS
9297 _Py_closerange(fd_low, fd_high - 1);
9298 Py_END_ALLOW_THREADS
9299 Py_RETURN_NONE;
9300 }
9301
9302
9303 /*[clinic input]
9304 os.dup -> int
9305
9306 fd: int
9307 /
9308
9309 Return a duplicate of a file descriptor.
9310 [clinic start generated code]*/
9311
9312 static int
9313 os_dup_impl(PyObject *module, int fd)
9314 /*[clinic end generated code: output=486f4860636b2a9f input=6f10f7ea97f7852a]*/
9315 {
9316 return _Py_dup(fd);
9317 }
9318
9319
9320 /*[clinic input]
9321 os.dup2 -> int
9322 fd: int
9323 fd2: int
9324 inheritable: bool=True
9325
9326 Duplicate file descriptor.
9327 [clinic start generated code]*/
9328
9329 static int
9330 os_dup2_impl(PyObject *module, int fd, int fd2, int inheritable)
9331 /*[clinic end generated code: output=bc059d34a73404d1 input=c3cddda8922b038d]*/
9332 {
9333 int res = 0;
9334 #if defined(HAVE_DUP3) && \
9335 !(defined(HAVE_FCNTL_H) && defined(F_DUP2FD_CLOEXEC))
9336 /* dup3() is available on Linux 2.6.27+ and glibc 2.9 */
9337 static int dup3_works = -1;
9338 #endif
9339
9340 if (fd < 0 || fd2 < 0) {
9341 posix_error();
9342 return -1;
9343 }
9344
9345 /* dup2() can fail with EINTR if the target FD is already open, because it
9346 * then has to be closed. See os_close_impl() for why we don't handle EINTR
9347 * upon close(), and therefore below.
9348 */
9349 #ifdef MS_WINDOWS
9350 Py_BEGIN_ALLOW_THREADS
9351 _Py_BEGIN_SUPPRESS_IPH
9352 res = dup2(fd, fd2);
9353 _Py_END_SUPPRESS_IPH
9354 Py_END_ALLOW_THREADS
9355 if (res < 0) {
9356 posix_error();
9357 return -1;
9358 }
9359 res = fd2; // msvcrt dup2 returns 0 on success.
9360
9361 /* Character files like console cannot be make non-inheritable */
9362 if (!inheritable && _Py_set_inheritable(fd2, 0, NULL) < 0) {
9363 close(fd2);
9364 return -1;
9365 }
9366
9367 #elif defined(HAVE_FCNTL_H) && defined(F_DUP2FD_CLOEXEC)
9368 Py_BEGIN_ALLOW_THREADS
9369 if (!inheritable)
9370 res = fcntl(fd, F_DUP2FD_CLOEXEC, fd2);
9371 else
9372 res = dup2(fd, fd2);
9373 Py_END_ALLOW_THREADS
9374 if (res < 0) {
9375 posix_error();
9376 return -1;
9377 }
9378
9379 #else
9380
9381 #ifdef HAVE_DUP3
9382 if (!inheritable && dup3_works != 0) {
9383 Py_BEGIN_ALLOW_THREADS
9384 res = dup3(fd, fd2, O_CLOEXEC);
9385 Py_END_ALLOW_THREADS
9386 if (res < 0) {
9387 if (dup3_works == -1)
9388 dup3_works = (errno != ENOSYS);
9389 if (dup3_works) {
9390 posix_error();
9391 return -1;
9392 }
9393 }
9394 }
9395
9396 if (inheritable || dup3_works == 0)
9397 {
9398 #endif
9399 Py_BEGIN_ALLOW_THREADS
9400 res = dup2(fd, fd2);
9401 Py_END_ALLOW_THREADS
9402 if (res < 0) {
9403 posix_error();
9404 return -1;
9405 }
9406
9407 if (!inheritable && _Py_set_inheritable(fd2, 0, NULL) < 0) {
9408 close(fd2);
9409 return -1;
9410 }
9411 #ifdef HAVE_DUP3
9412 }
9413 #endif
9414
9415 #endif
9416
9417 return res;
9418 }
9419
9420
9421 #ifdef HAVE_LOCKF
9422 /*[clinic input]
9423 os.lockf
9424
9425 fd: int
9426 An open file descriptor.
9427 command: int
9428 One of F_LOCK, F_TLOCK, F_ULOCK or F_TEST.
9429 length: Py_off_t
9430 The number of bytes to lock, starting at the current position.
9431 /
9432
9433 Apply, test or remove a POSIX lock on an open file descriptor.
9434
9435 [clinic start generated code]*/
9436
9437 static PyObject *
9438 os_lockf_impl(PyObject *module, int fd, int command, Py_off_t length)
9439 /*[clinic end generated code: output=af7051f3e7c29651 input=65da41d2106e9b79]*/
9440 {
9441 int res;
9442
9443 if (PySys_Audit("os.lockf", "iiL", fd, command, length) < 0) {
9444 return NULL;
9445 }
9446
9447 Py_BEGIN_ALLOW_THREADS
9448 res = lockf(fd, command, length);
9449 Py_END_ALLOW_THREADS
9450
9451 if (res < 0)
9452 return posix_error();
9453
9454 Py_RETURN_NONE;
9455 }
9456 #endif /* HAVE_LOCKF */
9457
9458
9459 /*[clinic input]
9460 os.lseek -> Py_off_t
9461
9462 fd: int
9463 position: Py_off_t
9464 how: int
9465 /
9466
9467 Set the position of a file descriptor. Return the new position.
9468
9469 Return the new cursor position in number of bytes
9470 relative to the beginning of the file.
9471 [clinic start generated code]*/
9472
9473 static Py_off_t
9474 os_lseek_impl(PyObject *module, int fd, Py_off_t position, int how)
9475 /*[clinic end generated code: output=971e1efb6b30bd2f input=902654ad3f96a6d3]*/
9476 {
9477 Py_off_t result;
9478
9479 #ifdef SEEK_SET
9480 /* Turn 0, 1, 2 into SEEK_{SET,CUR,END} */
9481 switch (how) {
9482 case 0: how = SEEK_SET; break;
9483 case 1: how = SEEK_CUR; break;
9484 case 2: how = SEEK_END; break;
9485 }
9486 #endif /* SEEK_END */
9487
9488 Py_BEGIN_ALLOW_THREADS
9489 _Py_BEGIN_SUPPRESS_IPH
9490 #ifdef MS_WINDOWS
9491 result = _lseeki64(fd, position, how);
9492 #else
9493 result = lseek(fd, position, how);
9494 #endif
9495 _Py_END_SUPPRESS_IPH
9496 Py_END_ALLOW_THREADS
9497 if (result < 0)
9498 posix_error();
9499
9500 return result;
9501 }
9502
9503
9504 /*[clinic input]
9505 os.read
9506 fd: int
9507 length: Py_ssize_t
9508 /
9509
9510 Read from a file descriptor. Returns a bytes object.
9511 [clinic start generated code]*/
9512
9513 static PyObject *
9514 7002 os_read_impl(PyObject *module, int fd, Py_ssize_t length)
9515 /*[clinic end generated code: output=dafbe9a5cddb987b input=1df2eaa27c0bf1d3]*/
9516 {
9517 Py_ssize_t n;
9518 PyObject *buffer;
9519
9520
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7002 times.
7002 if (length < 0) {
9521 errno = EINVAL;
9522 return posix_error();
9523 }
9524
9525 7002 length = Py_MIN(length, _PY_READ_MAX);
9526
9527 7002 buffer = PyBytes_FromStringAndSize((char *)NULL, length);
9528
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7002 times.
7002 if (buffer == NULL)
9529 return NULL;
9530
9531 7002 n = _Py_read(fd, PyBytes_AS_STRING(buffer), length);
9532
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7002 times.
7002 if (n == -1) {
9533 Py_DECREF(buffer);
9534 return NULL;
9535 }
9536
9537
1/2
✓ Branch 0 taken 7002 times.
✗ Branch 1 not taken.
7002 if (n != length)
9538 7002 _PyBytes_Resize(&buffer, n);
9539
9540 7002 return buffer;
9541 }
9542
9543 #if (defined(HAVE_SENDFILE) && (defined(__FreeBSD__) || defined(__DragonFly__) \
9544 || defined(__APPLE__))) \
9545 || defined(HAVE_READV) || defined(HAVE_PREADV) || defined (HAVE_PREADV2) \
9546 || defined(HAVE_WRITEV) || defined(HAVE_PWRITEV) || defined (HAVE_PWRITEV2)
9547 static int
9548 iov_setup(struct iovec **iov, Py_buffer **buf, PyObject *seq, Py_ssize_t cnt, int type)
9549 {
9550 Py_ssize_t i, j;
9551
9552 *iov = PyMem_New(struct iovec, cnt);
9553 if (*iov == NULL) {
9554 PyErr_NoMemory();
9555 return -1;
9556 }
9557
9558 *buf = PyMem_New(Py_buffer, cnt);
9559 if (*buf == NULL) {
9560 PyMem_Free(*iov);
9561 PyErr_NoMemory();
9562 return -1;
9563 }
9564
9565 for (i = 0; i < cnt; i++) {
9566 PyObject *item = PySequence_GetItem(seq, i);
9567 if (item == NULL)
9568 goto fail;
9569 if (PyObject_GetBuffer(item, &(*buf)[i], type) == -1) {
9570 Py_DECREF(item);
9571 goto fail;
9572 }
9573 Py_DECREF(item);
9574 (*iov)[i].iov_base = (*buf)[i].buf;
9575 (*iov)[i].iov_len = (*buf)[i].len;
9576 }
9577 return 0;
9578
9579 fail:
9580 PyMem_Free(*iov);
9581 for (j = 0; j < i; j++) {
9582 PyBuffer_Release(&(*buf)[j]);
9583 }
9584 PyMem_Free(*buf);
9585 return -1;
9586 }
9587
9588 static void
9589 iov_cleanup(struct iovec *iov, Py_buffer *buf, int cnt)
9590 {
9591 int i;
9592 PyMem_Free(iov);
9593 for (i = 0; i < cnt; i++) {
9594 PyBuffer_Release(&buf[i]);
9595 }
9596 PyMem_Free(buf);
9597 }
9598 #endif
9599
9600
9601 #ifdef HAVE_READV
9602 /*[clinic input]
9603 os.readv -> Py_ssize_t
9604
9605 fd: int
9606 buffers: object
9607 /
9608
9609 Read from a file descriptor fd into an iterable of buffers.
9610
9611 The buffers should be mutable buffers accepting bytes.
9612 readv will transfer data into each buffer until it is full
9613 and then move on to the next buffer in the sequence to hold
9614 the rest of the data.
9615
9616 readv returns the total number of bytes read,
9617 which may be less than the total capacity of all the buffers.
9618 [clinic start generated code]*/
9619
9620 static Py_ssize_t
9621 os_readv_impl(PyObject *module, int fd, PyObject *buffers)
9622 /*[clinic end generated code: output=792da062d3fcebdb input=e679eb5dbfa0357d]*/
9623 {
9624 Py_ssize_t cnt, n;
9625 int async_err = 0;
9626 struct iovec *iov;
9627 Py_buffer *buf;
9628
9629 if (!PySequence_Check(buffers)) {
9630 PyErr_SetString(PyExc_TypeError,
9631 "readv() arg 2 must be a sequence");
9632 return -1;
9633 }
9634
9635 cnt = PySequence_Size(buffers);
9636 if (cnt < 0)
9637 return -1;
9638
9639 if (iov_setup(&iov, &buf, buffers, cnt, PyBUF_WRITABLE) < 0)
9640 return -1;
9641
9642 do {
9643 Py_BEGIN_ALLOW_THREADS
9644 n = readv(fd, iov, cnt);
9645 Py_END_ALLOW_THREADS
9646 } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
9647
9648 iov_cleanup(iov, buf, cnt);
9649 if (n < 0) {
9650 if (!async_err)
9651 posix_error();
9652 return -1;
9653 }
9654
9655 return n;
9656 }
9657 #endif /* HAVE_READV */
9658
9659
9660 #ifdef HAVE_PREAD
9661 /*[clinic input]
9662 os.pread
9663
9664 fd: int
9665 length: Py_ssize_t
9666 offset: Py_off_t
9667 /
9668
9669 Read a number of bytes from a file descriptor starting at a particular offset.
9670
9671 Read length bytes from file descriptor fd, starting at offset bytes from
9672 the beginning of the file. The file offset remains unchanged.
9673 [clinic start generated code]*/
9674
9675 static PyObject *
9676 os_pread_impl(PyObject *module, int fd, Py_ssize_t length, Py_off_t offset)
9677 /*[clinic end generated code: output=3f875c1eef82e32f input=85cb4a5589627144]*/
9678 {
9679 Py_ssize_t n;
9680 int async_err = 0;
9681 PyObject *buffer;
9682
9683 if (length < 0) {
9684 errno = EINVAL;
9685 return posix_error();
9686 }
9687 buffer = PyBytes_FromStringAndSize((char *)NULL, length);
9688 if (buffer == NULL)
9689 return NULL;
9690
9691 do {
9692 Py_BEGIN_ALLOW_THREADS
9693 _Py_BEGIN_SUPPRESS_IPH
9694 n = pread(fd, PyBytes_AS_STRING(buffer), length, offset);
9695 _Py_END_SUPPRESS_IPH
9696 Py_END_ALLOW_THREADS
9697 } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
9698
9699 if (n < 0) {
9700 Py_DECREF(buffer);
9701 return (!async_err) ? posix_error() : NULL;
9702 }
9703 if (n != length)
9704 _PyBytes_Resize(&buffer, n);
9705 return buffer;
9706 }
9707 #endif /* HAVE_PREAD */
9708
9709 #if defined(HAVE_PREADV) || defined (HAVE_PREADV2)
9710 /*[clinic input]
9711 os.preadv -> Py_ssize_t
9712
9713 fd: int
9714 buffers: object
9715 offset: Py_off_t
9716 flags: int = 0
9717 /
9718
9719 Reads from a file descriptor into a number of mutable bytes-like objects.
9720
9721 Combines the functionality of readv() and pread(). As readv(), it will
9722 transfer data into each buffer until it is full and then move on to the next
9723 buffer in the sequence to hold the rest of the data. Its fourth argument,
9724 specifies the file offset at which the input operation is to be performed. It
9725 will return the total number of bytes read (which can be less than the total
9726 capacity of all the objects).
9727
9728 The flags argument contains a bitwise OR of zero or more of the following flags:
9729
9730 - RWF_HIPRI
9731 - RWF_NOWAIT
9732
9733 Using non-zero flags requires Linux 4.6 or newer.
9734 [clinic start generated code]*/
9735
9736 static Py_ssize_t
9737 os_preadv_impl(PyObject *module, int fd, PyObject *buffers, Py_off_t offset,
9738 int flags)
9739 /*[clinic end generated code: output=26fc9c6e58e7ada5 input=4173919dc1f7ed99]*/
9740 {
9741 Py_ssize_t cnt, n;
9742 int async_err = 0;
9743 struct iovec *iov;
9744 Py_buffer *buf;
9745
9746 if (!PySequence_Check(buffers)) {
9747 PyErr_SetString(PyExc_TypeError,
9748 "preadv2() arg 2 must be a sequence");
9749 return -1;
9750 }
9751
9752 cnt = PySequence_Size(buffers);
9753 if (cnt < 0) {
9754 return -1;
9755 }
9756
9757 #ifndef HAVE_PREADV2
9758 if(flags != 0) {
9759 argument_unavailable_error("preadv2", "flags");
9760 return -1;
9761 }
9762 #endif
9763
9764 if (iov_setup(&iov, &buf, buffers, cnt, PyBUF_WRITABLE) < 0) {
9765 return -1;
9766 }
9767 #ifdef HAVE_PREADV2
9768 do {
9769 Py_BEGIN_ALLOW_THREADS
9770 _Py_BEGIN_SUPPRESS_IPH
9771 n = preadv2(fd, iov, cnt, offset, flags);
9772 _Py_END_SUPPRESS_IPH
9773 Py_END_ALLOW_THREADS
9774 } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
9775 #else
9776 do {
9777 #ifdef __APPLE__
9778 /* This entire function will be removed from the module dict when the API
9779 * is not available.
9780 */
9781 #pragma clang diagnostic push
9782 #pragma clang diagnostic ignored "-Wunguarded-availability"
9783 #pragma clang diagnostic ignored "-Wunguarded-availability-new"
9784 #endif
9785 Py_BEGIN_ALLOW_THREADS
9786 _Py_BEGIN_SUPPRESS_IPH
9787 n = preadv(fd, iov, cnt, offset);
9788 _Py_END_SUPPRESS_IPH
9789 Py_END_ALLOW_THREADS
9790 } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
9791
9792 #ifdef __APPLE__
9793 #pragma clang diagnostic pop
9794 #endif
9795
9796 #endif
9797
9798 iov_cleanup(iov, buf, cnt);
9799 if (n < 0) {
9800 if (!async_err) {
9801 posix_error();
9802 }
9803 return -1;
9804 }
9805
9806 return n;
9807 }
9808 #endif /* HAVE_PREADV */
9809
9810
9811 /*[clinic input]
9812 os.write -> Py_ssize_t
9813
9814 fd: int
9815 data: Py_buffer
9816 /
9817
9818 Write a bytes object to a file descriptor.
9819 [clinic start generated code]*/
9820
9821 static Py_ssize_t
9822 1 os_write_impl(PyObject *module, int fd, Py_buffer *data)
9823 /*[clinic end generated code: output=e4ef5bc904b58ef9 input=3207e28963234f3c]*/
9824 {
9825 1 return _Py_write(fd, data->buf, data->len);
9826 }
9827
9828 #ifdef HAVE_SENDFILE
9829 #ifdef __APPLE__
9830 /*[clinic input]
9831 os.sendfile
9832
9833 out_fd: int
9834 in_fd: int
9835 offset: Py_off_t
9836 count as sbytes: Py_off_t
9837 headers: object(c_default="NULL") = ()
9838 trailers: object(c_default="NULL") = ()
9839 flags: int = 0
9840
9841 Copy count bytes from file descriptor in_fd to file descriptor out_fd.
9842 [clinic start generated code]*/
9843
9844 static PyObject *
9845 os_sendfile_impl(PyObject *module, int out_fd, int in_fd, Py_off_t offset,
9846 Py_off_t sbytes, PyObject *headers, PyObject *trailers,
9847 int flags)
9848 /*[clinic end generated code: output=81c4bcd143f5c82b input=b0d72579d4c69afa]*/
9849 #elif defined(__FreeBSD__) || defined(__DragonFly__)
9850 /*[clinic input]
9851 os.sendfile
9852
9853 out_fd: int
9854 in_fd: int
9855 offset: Py_off_t
9856 count: Py_ssize_t
9857 headers: object(c_default="NULL") = ()
9858 trailers: object(c_default="NULL") = ()
9859 flags: int = 0
9860
9861 Copy count bytes from file descriptor in_fd to file descriptor out_fd.
9862 [clinic start generated code]*/
9863
9864 static PyObject *
9865 os_sendfile_impl(PyObject *module, int out_fd, int in_fd, Py_off_t offset,
9866 Py_ssize_t count, PyObject *headers, PyObject *trailers,
9867 int flags)
9868 /*[clinic end generated code: output=329ea009bdd55afc input=338adb8ff84ae8cd]*/
9869 #else
9870 /*[clinic input]
9871 os.sendfile
9872
9873 out_fd: int
9874 in_fd: int
9875 offset as offobj: object
9876 count: Py_ssize_t
9877
9878 Copy count bytes from file descriptor in_fd to file descriptor out_fd.
9879 [clinic start generated code]*/
9880
9881 static PyObject *
9882 140 os_sendfile_impl(PyObject *module, int out_fd, int in_fd, PyObject *offobj,
9883 Py_ssize_t count)
9884 /*[clinic end generated code: output=ae81216e40f167d8 input=76d64058c74477ba]*/
9885 #endif
9886 {
9887 Py_ssize_t ret;
9888 140 int async_err = 0;
9889
9890 #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__APPLE__)
9891 #ifndef __APPLE__
9892 off_t sbytes;
9893 #endif
9894 Py_buffer *hbuf, *tbuf;
9895 struct sf_hdtr sf;
9896
9897 sf.headers = NULL;
9898 sf.trailers = NULL;
9899
9900 if (headers != NULL) {
9901 if (!PySequence_Check(headers)) {
9902 PyErr_SetString(PyExc_TypeError,
9903 "sendfile() headers must be a sequence");
9904 return NULL;
9905 } else {
9906 Py_ssize_t i = PySequence_Size(headers);
9907 if (i < 0)
9908 return NULL;
9909 if (i > INT_MAX) {
9910 PyErr_SetString(PyExc_OverflowError,
9911 "sendfile() header is too large");
9912 return NULL;
9913 }
9914 if (i > 0) {
9915 sf.hdr_cnt = (int)i;
9916 if (iov_setup(&(sf.headers), &hbuf,
9917 headers, sf.hdr_cnt, PyBUF_SIMPLE) < 0)
9918 return NULL;
9919 #ifdef __APPLE__
9920 for (i = 0; i < sf.hdr_cnt; i++) {
9921 Py_ssize_t blen = sf.headers[i].iov_len;
9922 # define OFF_T_MAX 0x7fffffffffffffff
9923 if (sbytes >= OFF_T_MAX - blen) {
9924 PyErr_SetString(PyExc_OverflowError,
9925 "sendfile() header is too large");
9926 return NULL;
9927 }
9928 sbytes += blen;
9929 }
9930 #endif
9931 }
9932 }
9933 }
9934 if (trailers != NULL) {
9935 if (!PySequence_Check(trailers)) {
9936 PyErr_SetString(PyExc_TypeError,
9937 "sendfile() trailers must be a sequence");
9938 return NULL;
9939 } else {
9940 Py_ssize_t i = PySequence_Size(trailers);
9941 if (i < 0)
9942 return NULL;
9943 if (i > INT_MAX) {
9944 PyErr_SetString(PyExc_OverflowError,
9945 "sendfile() trailer is too large");
9946 return NULL;
9947 }
9948 if (i > 0) {
9949 sf.trl_cnt = (int)i;
9950 if (iov_setup(&(sf.trailers), &tbuf,
9951 trailers, sf.trl_cnt, PyBUF_SIMPLE) < 0)
9952 return NULL;
9953 }
9954 }
9955 }
9956
9957 _Py_BEGIN_SUPPRESS_IPH
9958 do {
9959 Py_BEGIN_ALLOW_THREADS
9960 #ifdef __APPLE__
9961 ret = sendfile(in_fd, out_fd, offset, &sbytes, &sf, flags);
9962 #else
9963 ret = sendfile(in_fd, out_fd, offset, count, &sf, &sbytes, flags);
9964 #endif
9965 Py_END_ALLOW_THREADS
9966 } while (ret < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
9967 _Py_END_SUPPRESS_IPH
9968
9969 if (sf.headers != NULL)
9970 iov_cleanup(sf.headers, hbuf, sf.hdr_cnt);
9971 if (sf.trailers != NULL)
9972 iov_cleanup(sf.trailers, tbuf, sf.trl_cnt);
9973
9974 if (ret < 0) {
9975 if ((errno == EAGAIN) || (errno == EBUSY)) {
9976 if (sbytes != 0) {
9977 // some data has been sent
9978 goto done;
9979 }
9980 else {
9981 // no data has been sent; upper application is supposed
9982 // to retry on EAGAIN or EBUSY
9983 return posix_error();
9984 }
9985 }
9986 return (!async_err) ? posix_error() : NULL;
9987 }
9988 goto done;
9989
9990 done:
9991 #if !defined(HAVE_LARGEFILE_SUPPORT)
9992 return Py_BuildValue("l", sbytes);
9993 #else
9994 return Py_BuildValue("L", sbytes);
9995 #endif
9996
9997 #else
9998 #ifdef __linux__
9999
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 140 times.
140 if (offobj == Py_None) {
10000 do {
10001 Py_BEGIN_ALLOW_THREADS
10002 ret = sendfile(out_fd, in_fd, NULL, count);
10003 Py_END_ALLOW_THREADS
10004 } while (ret < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
10005 if (ret < 0)
10006 return (!async_err) ? posix_error() : NULL;
10007 return Py_BuildValue("n", ret);
10008 }
10009 #endif
10010 off_t offset;
10011
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 140 times.
140 if (!Py_off_t_converter(offobj, &offset))
10012 return NULL;
10013
10014 #if defined(__sun) && defined(__SVR4)
10015 // On Solaris, sendfile raises EINVAL rather than returning 0
10016 // when the offset is equal or bigger than the in_fd size.
10017 struct stat st;
10018
10019 do {
10020 Py_BEGIN_ALLOW_THREADS
10021 ret = fstat(in_fd, &st);
10022 Py_END_ALLOW_THREADS
10023 } while (ret != 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
10024 if (ret < 0)
10025 return (!async_err) ? posix_error() : NULL;
10026
10027 if (offset >= st.st_size) {
10028 return Py_BuildValue("i", 0);
10029 }
10030
10031 // On illumos specifically sendfile() may perform a partial write but
10032 // return -1/an error (in one confirmed case the destination socket
10033 // had a 5 second timeout set and errno was EAGAIN) and it's on the client
10034 // code to check if the offset parameter was modified by sendfile().
10035 //
10036 // We need this variable to track said change.
10037 off_t original_offset = offset;
10038 #endif
10039
10040 do {
10041 140 Py_BEGIN_ALLOW_THREADS
10042 140 ret = sendfile(out_fd, in_fd, &offset, count);
10043 #if defined(__sun) && defined(__SVR4)
10044 // This handles illumos-specific sendfile() partial write behavior,
10045 // see a comment above for more details.
10046 if (ret < 0 && offset != original_offset) {
10047 ret = offset - original_offset;
10048 }
10049 #endif
10050 140 Py_END_ALLOW_THREADS
10051
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 140 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
140 } while (ret < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
10052
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 140 times.
140 if (ret < 0)
10053 return (!async_err) ? posix_error() : NULL;
10054 140 return Py_BuildValue("n", ret);
10055 #endif
10056 }
10057 #endif /* HAVE_SENDFILE */
10058
10059
10060 #if defined(__APPLE__)
10061 /*[clinic input]
10062 os._fcopyfile
10063
10064 in_fd: int
10065 out_fd: int
10066 flags: int
10067 /
10068
10069 Efficiently copy content or metadata of 2 regular file descriptors (macOS).
10070 [clinic start generated code]*/
10071
10072 static PyObject *
10073 os__fcopyfile_impl(PyObject *module, int in_fd, int out_fd, int flags)
10074 /*[clinic end generated code: output=c9d1a35a992e401b input=1e34638a86948795]*/
10075 {
10076 int ret;
10077
10078 Py_BEGIN_ALLOW_THREADS
10079 ret = fcopyfile(in_fd, out_fd, NULL, flags);
10080 Py_END_ALLOW_THREADS
10081 if (ret < 0)
10082 return posix_error();
10083 Py_RETURN_NONE;
10084 }
10085 #endif
10086
10087
10088 /*[clinic input]
10089 os.fstat
10090
10091 fd : int
10092
10093 Perform a stat system call on the given file descriptor.
10094
10095 Like stat(), but for an open file descriptor.
10096 Equivalent to os.stat(fd).
10097 [clinic start generated code]*/
10098
10099 static PyObject *
10100 2059 os_fstat_impl(PyObject *module, int fd)
10101 /*[clinic end generated code: output=efc038cb5f654492 input=27e0e0ebbe5600c9]*/
10102 {
10103 STRUCT_STAT st;
10104 int res;
10105 2059 int async_err = 0;
10106
10107 do {
10108 2059 Py_BEGIN_ALLOW_THREADS
10109 2059 res = FSTAT(fd, &st);
10110 2059 Py_END_ALLOW_THREADS
10111
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 2059 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
2059 } while (res != 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
10112
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2059 times.
2059 if (res != 0) {
10113 #ifdef MS_WINDOWS
10114 return PyErr_SetFromWindowsErr(0);
10115 #else
10116 return (!async_err) ? posix_error() : NULL;
10117 #endif
10118 }
10119
10120 2059 return _pystat_fromstructstat(module, &st);
10121 }
10122
10123
10124 /*[clinic input]
10125 os.isatty -> bool
10126 fd: int
10127 /
10128
10129 Return True if the fd is connected to a terminal.
10130
10131 Return True if the file descriptor is an open file descriptor
10132 connected to the slave end of a terminal.
10133 [clinic start generated code]*/
10134
10135 static int
10136 os_isatty_impl(PyObject *module, int fd)
10137 /*[clinic end generated code: output=6a48c8b4e644ca00 input=08ce94aa1eaf7b5e]*/
10138 {
10139 int return_value;
10140 Py_BEGIN_ALLOW_THREADS
10141 _Py_BEGIN_SUPPRESS_IPH
10142 return_value = isatty(fd);
10143 _Py_END_SUPPRESS_IPH
10144 Py_END_ALLOW_THREADS
10145 return return_value;
10146 }
10147
10148
10149 #ifdef HAVE_PIPE
10150 /*[clinic input]
10151 os.pipe
10152
10153 Create a pipe.
10154
10155 Returns a tuple of two file descriptors:
10156 (read_fd, write_fd)
10157 [clinic start generated code]*/
10158
10159 static PyObject *
10160 12058 os_pipe_impl(PyObject *module)
10161 /*[clinic end generated code: output=ff9b76255793b440 input=02535e8c8fa6c4d4]*/
10162 {
10163 int fds[2];
10164 #ifdef MS_WINDOWS
10165 HANDLE read, write;
10166 SECURITY_ATTRIBUTES attr;
10167 BOOL ok;
10168 #else
10169 int res;
10170 #endif
10171
10172 #ifdef MS_WINDOWS
10173 attr.nLength = sizeof(attr);
10174 attr.lpSecurityDescriptor = NULL;
10175 attr.bInheritHandle = FALSE;
10176
10177 Py_BEGIN_ALLOW_THREADS
10178 ok = CreatePipe(&read, &write, &attr, 0);
10179 if (ok) {
10180 fds[0] = _Py_open_osfhandle_noraise(read, _O_RDONLY);
10181 fds[1] = _Py_open_osfhandle_noraise(write, _O_WRONLY);
10182 if (fds[0] == -1 || fds[1] == -1) {
10183 CloseHandle(read);
10184 CloseHandle(write);
10185 ok = 0;
10186 }
10187 }
10188 Py_END_ALLOW_THREADS
10189
10190 if (!ok)
10191 return PyErr_SetFromWindowsErr(0);
10192 #else
10193
10194 #ifdef HAVE_PIPE2
10195 12058 Py_BEGIN_ALLOW_THREADS
10196 12058 res = pipe2(fds, O_CLOEXEC);
10197 12058 Py_END_ALLOW_THREADS
10198
10199
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 12058 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
12058 if (res != 0 && errno == ENOSYS)
10200 {
10201 #endif
10202 Py_BEGIN_ALLOW_THREADS
10203 res = pipe(fds);
10204 Py_END_ALLOW_THREADS
10205
10206 if (res == 0) {
10207 if (_Py_set_inheritable(fds[0], 0, NULL) < 0) {
10208 close(fds[0]);
10209 close(fds[1]);
10210 return NULL;
10211 }
10212 if (_Py_set_inheritable(fds[1], 0, NULL) < 0) {
10213 close(fds[0]);
10214 close(fds[1]);
10215 return NULL;
10216 }
10217 }
10218 #ifdef HAVE_PIPE2
10219 }
10220 #endif
10221
10222
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12058 times.
12058 if (res != 0)
10223 return PyErr_SetFromErrno(PyExc_OSError);
10224 #endif /* !MS_WINDOWS */
10225 12058 return Py_BuildValue("(ii)", fds[0], fds[1]);
10226 }
10227 #endif /* HAVE_PIPE */
10228
10229
10230 #ifdef HAVE_PIPE2
10231 /*[clinic input]
10232 os.pipe2
10233
10234 flags: int
10235 /
10236
10237 Create a pipe with flags set atomically.
10238
10239 Returns a tuple of two file descriptors:
10240 (read_fd, write_fd)
10241
10242 flags can be constructed by ORing together one or more of these values:
10243 O_NONBLOCK, O_CLOEXEC.
10244 [clinic start generated code]*/
10245
10246 static PyObject *
10247 os_pipe2_impl(PyObject *module, int flags)
10248 /*[clinic end generated code: output=25751fb43a45540f input=f261b6e7e63c6817]*/
10249 {
10250 int fds[2];
10251 int res;
10252
10253 res = pipe2(fds, flags);
10254 if (res != 0)
10255 return posix_error();
10256 return Py_BuildValue("(ii)", fds[0], fds[1]);
10257 }
10258 #endif /* HAVE_PIPE2 */
10259
10260
10261 #ifdef HAVE_WRITEV
10262 /*[clinic input]
10263 os.writev -> Py_ssize_t
10264 fd: int
10265 buffers: object
10266 /
10267
10268 Iterate over buffers, and write the contents of each to a file descriptor.
10269
10270 Returns the total number of bytes written.
10271 buffers must be a sequence of bytes-like objects.
10272 [clinic start generated code]*/
10273
10274 static Py_ssize_t
10275 os_writev_impl(PyObject *module, int fd, PyObject *buffers)
10276 /*[clinic end generated code: output=56565cfac3aac15b input=5b8d17fe4189d2fe]*/
10277 {
10278 Py_ssize_t cnt;
10279 Py_ssize_t result;
10280 int async_err = 0;
10281 struct iovec *iov;
10282 Py_buffer *buf;
10283
10284 if (!PySequence_Check(buffers)) {
10285 PyErr_SetString(PyExc_TypeError,
10286 "writev() arg 2 must be a sequence");
10287 return -1;
10288 }
10289 cnt = PySequence_Size(buffers);
10290 if (cnt < 0)
10291 return -1;
10292
10293 if (iov_setup(&iov, &buf, buffers, cnt, PyBUF_SIMPLE) < 0) {
10294 return -1;
10295 }
10296
10297 do {
10298 Py_BEGIN_ALLOW_THREADS
10299 result = writev(fd, iov, cnt);
10300 Py_END_ALLOW_THREADS
10301 } while (result < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
10302
10303 iov_cleanup(iov, buf, cnt);
10304 if (result < 0 && !async_err)
10305 posix_error();
10306
10307 return result;
10308 }
10309 #endif /* HAVE_WRITEV */
10310
10311
10312 #ifdef HAVE_PWRITE
10313 /*[clinic input]
10314 os.pwrite -> Py_ssize_t
10315
10316 fd: int
10317 buffer: Py_buffer
10318 offset: Py_off_t
10319 /
10320
10321 Write bytes to a file descriptor starting at a particular offset.
10322
10323 Write buffer to fd, starting at offset bytes from the beginning of
10324 the file. Returns the number of bytes writte. Does not change the
10325 current file offset.
10326 [clinic start generated code]*/
10327
10328 static Py_ssize_t
10329 os_pwrite_impl(PyObject *module, int fd, Py_buffer *buffer, Py_off_t offset)
10330 /*[clinic end generated code: output=c74da630758ee925 input=19903f1b3dd26377]*/
10331 {
10332 Py_ssize_t size;
10333 int async_err = 0;
10334
10335 do {
10336 Py_BEGIN_ALLOW_THREADS
10337 _Py_BEGIN_SUPPRESS_IPH
10338 size = pwrite(fd, buffer->buf, (size_t)buffer->len, offset);
10339 _Py_END_SUPPRESS_IPH
10340 Py_END_ALLOW_THREADS
10341 } while (size < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
10342
10343 if (size < 0 && !async_err)
10344 posix_error();
10345 return size;
10346 }
10347 #endif /* HAVE_PWRITE */
10348
10349 #if defined(HAVE_PWRITEV) || defined (HAVE_PWRITEV2)
10350 /*[clinic input]
10351 os.pwritev -> Py_ssize_t
10352
10353 fd: int
10354 buffers: object
10355 offset: Py_off_t
10356 flags: int = 0
10357 /
10358
10359 Writes the contents of bytes-like objects to a file descriptor at a given offset.
10360
10361 Combines the functionality of writev() and pwrite(). All buffers must be a sequence
10362 of bytes-like objects. Buffers are processed in array order. Entire contents of first
10363 buffer is written before proceeding to second, and so on. The operating system may
10364 set a limit (sysconf() value SC_IOV_MAX) on the number of buffers that can be used.
10365 This function writes the contents of each object to the file descriptor and returns
10366 the total number of bytes written.
10367
10368 The flags argument contains a bitwise OR of zero or more of the following flags:
10369
10370 - RWF_DSYNC
10371 - RWF_SYNC
10372 - RWF_APPEND
10373
10374 Using non-zero flags requires Linux 4.7 or newer.
10375 [clinic start generated code]*/
10376
10377 static Py_ssize_t
10378 os_pwritev_impl(PyObject *module, int fd, PyObject *buffers, Py_off_t offset,
10379 int flags)
10380 /*[clinic end generated code: output=e3dd3e9d11a6a5c7 input=35358c327e1a2a8e]*/
10381 {
10382 Py_ssize_t cnt;
10383 Py_ssize_t result;
10384 int async_err = 0;
10385 struct iovec *iov;
10386 Py_buffer *buf;
10387
10388 if (!PySequence_Check(buffers)) {
10389 PyErr_SetString(PyExc_TypeError,
10390 "pwritev() arg 2 must be a sequence");
10391 return -1;
10392 }
10393
10394 cnt = PySequence_Size(buffers);
10395 if (cnt < 0) {
10396 return -1;
10397 }
10398
10399 #ifndef HAVE_PWRITEV2
10400 if(flags != 0) {
10401 argument_unavailable_error("pwritev2", "flags");
10402 return -1;
10403 }
10404 #endif
10405
10406 if (iov_setup(&iov, &buf, buffers, cnt, PyBUF_SIMPLE) < 0) {
10407 return -1;
10408 }
10409 #ifdef HAVE_PWRITEV2
10410 do {
10411 Py_BEGIN_ALLOW_THREADS
10412 _Py_BEGIN_SUPPRESS_IPH
10413 result = pwritev2(fd, iov, cnt, offset, flags);
10414 _Py_END_SUPPRESS_IPH
10415 Py_END_ALLOW_THREADS
10416 } while (result < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
10417 #else
10418
10419 #ifdef __APPLE__
10420 /* This entire function will be removed from the module dict when the API
10421 * is not available.
10422 */
10423 #pragma clang diagnostic push
10424 #pragma clang diagnostic ignored "-Wunguarded-availability"
10425 #pragma clang diagnostic ignored "-Wunguarded-availability-new"
10426 #endif
10427 do {
10428 Py_BEGIN_ALLOW_THREADS
10429 _Py_BEGIN_SUPPRESS_IPH
10430 result = pwritev(fd, iov, cnt, offset);
10431 _Py_END_SUPPRESS_IPH
10432 Py_END_ALLOW_THREADS
10433 } while (result < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
10434
10435 #ifdef __APPLE__
10436 #pragma clang diagnostic pop
10437 #endif
10438
10439 #endif
10440
10441 iov_cleanup(iov, buf, cnt);
10442 if (result < 0) {
10443 if (!async_err) {
10444 posix_error();
10445 }
10446 return -1;
10447 }
10448
10449 return result;
10450 }
10451 #endif /* HAVE_PWRITEV */
10452
10453 #ifdef HAVE_COPY_FILE_RANGE
10454 /*[clinic input]
10455
10456 os.copy_file_range
10457 src: int
10458 Source file descriptor.
10459 dst: int
10460 Destination file descriptor.
10461 count: Py_ssize_t
10462 Number of bytes to copy.
10463 offset_src: object = None
10464 Starting offset in src.
10465 offset_dst: object = None
10466 Starting offset in dst.
10467
10468 Copy count bytes from one file descriptor to another.
10469
10470 If offset_src is None, then src is read from the current position;
10471 respectively for offset_dst.
10472 [clinic start generated code]*/
10473
10474 static PyObject *
10475 os_copy_file_range_impl(PyObject *module, int src, int dst, Py_ssize_t count,
10476 PyObject *offset_src, PyObject *offset_dst)
10477 /*[clinic end generated code: output=1a91713a1d99fc7a input=42fdce72681b25a9]*/
10478 {
10479 off_t offset_src_val, offset_dst_val;
10480 off_t *p_offset_src = NULL;
10481 off_t *p_offset_dst = NULL;
10482 Py_ssize_t ret;
10483 int async_err = 0;
10484 /* The flags argument is provided to allow
10485 * for future extensions and currently must be to 0. */
10486 int flags = 0;
10487
10488
10489 if (count < 0) {
10490 PyErr_SetString(PyExc_ValueError, "negative value for 'count' not allowed");
10491 return NULL;
10492 }
10493
10494 if (offset_src != Py_None) {
10495 if (!Py_off_t_converter(offset_src, &offset_src_val)) {
10496 return NULL;
10497 }
10498 p_offset_src = &offset_src_val;
10499 }
10500
10501 if (offset_dst != Py_None) {
10502 if (!Py_off_t_converter(offset_dst, &offset_dst_val)) {
10503 return NULL;
10504 }
10505 p_offset_dst = &offset_dst_val;
10506 }
10507
10508 do {
10509 Py_BEGIN_ALLOW_THREADS
10510 ret = copy_file_range(src, p_offset_src, dst, p_offset_dst, count, flags);
10511 Py_END_ALLOW_THREADS
10512 } while (ret < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
10513
10514 if (ret < 0) {
10515 return (!async_err) ? posix_error() : NULL;
10516 }
10517
10518 return PyLong_FromSsize_t(ret);
10519 }
10520 #endif /* HAVE_COPY_FILE_RANGE*/
10521
10522 #if (defined(HAVE_SPLICE) && !defined(_AIX))
10523 /*[clinic input]
10524
10525 os.splice
10526 src: int
10527 Source file descriptor.
10528 dst: int
10529 Destination file descriptor.
10530 count: Py_ssize_t
10531 Number of bytes to copy.
10532 offset_src: object = None
10533 Starting offset in src.
10534 offset_dst: object = None
10535 Starting offset in dst.
10536 flags: unsigned_int = 0
10537 Flags to modify the semantics of the call.
10538
10539 Transfer count bytes from one pipe to a descriptor or vice versa.
10540
10541 If offset_src is None, then src is read from the current position;
10542 respectively for offset_dst. The offset associated to the file
10543 descriptor that refers to a pipe must be None.
10544 [clinic start generated code]*/
10545
10546 static PyObject *
10547 os_splice_impl(PyObject *module, int src, int dst, Py_ssize_t count,
10548 PyObject *offset_src, PyObject *offset_dst,
10549 unsigned int flags)
10550 /*[clinic end generated code: output=d0386f25a8519dc5 input=047527c66c6d2e0a]*/
10551 {
10552 off_t offset_src_val, offset_dst_val;
10553 off_t *p_offset_src = NULL;
10554 off_t *p_offset_dst = NULL;
10555 Py_ssize_t ret;
10556 int async_err = 0;
10557
10558 if (count < 0) {
10559 PyErr_SetString(PyExc_ValueError, "negative value for 'count' not allowed");
10560 return NULL;
10561 }
10562
10563 if (offset_src != Py_None) {
10564 if (!Py_off_t_converter(offset_src, &offset_src_val)) {
10565 return NULL;
10566 }
10567 p_offset_src = &offset_src_val;
10568 }
10569
10570 if (offset_dst != Py_None) {
10571 if (!Py_off_t_converter(offset_dst, &offset_dst_val)) {
10572 return NULL;
10573 }
10574 p_offset_dst = &offset_dst_val;
10575 }
10576
10577 do {
10578 Py_BEGIN_ALLOW_THREADS
10579 ret = splice(src, p_offset_src, dst, p_offset_dst, count, flags);
10580 Py_END_ALLOW_THREADS
10581 } while (ret < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
10582
10583 if (ret < 0) {
10584 return (!async_err) ? posix_error() : NULL;
10585 }
10586
10587 return PyLong_FromSsize_t(ret);
10588 }
10589 #endif /* HAVE_SPLICE*/
10590
10591 #ifdef HAVE_MKFIFO
10592 /*[clinic input]
10593 os.mkfifo
10594
10595 path: path_t
10596 mode: int=0o666
10597 *
10598 dir_fd: dir_fd(requires='mkfifoat')=None
10599
10600 Create a "fifo" (a POSIX named pipe).
10601
10602 If dir_fd is not None, it should be a file descriptor open to a directory,
10603 and path should be relative; path will then be relative to that directory.
10604 dir_fd may not be implemented on your platform.
10605 If it is unavailable, using it will raise a NotImplementedError.
10606 [clinic start generated code]*/
10607
10608 static PyObject *
10609 os_mkfifo_impl(PyObject *module, path_t *path, int mode, int dir_fd)
10610 /*[clinic end generated code: output=ce41cfad0e68c940 input=73032e98a36e0e19]*/
10611 {
10612 int result;
10613 int async_err = 0;
10614
10615 do {
10616 Py_BEGIN_ALLOW_THREADS
10617 #ifdef HAVE_MKFIFOAT
10618 if (dir_fd != DEFAULT_DIR_FD)
10619 result = mkfifoat(dir_fd, path->narrow, mode);
10620 else
10621 #endif
10622 result = mkfifo(path->narrow, mode);
10623 Py_END_ALLOW_THREADS
10624 } while (result != 0 && errno == EINTR &&
10625 !(async_err = PyErr_CheckSignals()));
10626 if (result != 0)
10627 return (!async_err) ? posix_error() : NULL;
10628
10629 Py_RETURN_NONE;
10630 }
10631 #endif /* HAVE_MKFIFO */
10632
10633
10634 #if defined(HAVE_MKNOD) && defined(HAVE_MAKEDEV)
10635 /*[clinic input]
10636 os.mknod
10637
10638 path: path_t
10639 mode: int=0o600
10640 device: dev_t=0
10641 *
10642 dir_fd: dir_fd(requires='mknodat')=None
10643
10644 Create a node in the file system.
10645
10646 Create a node in the file system (file, device special file or named pipe)
10647 at path. mode specifies both the permissions to use and the
10648 type of node to be created, being combined (bitwise OR) with one of
10649 S_IFREG, S_IFCHR, S_IFBLK, and S_IFIFO. If S_IFCHR or S_IFBLK is set on mode,
10650 device defines the newly created device special file (probably using
10651 os.makedev()). Otherwise device is ignored.
10652
10653 If dir_fd is not None, it should be a file descriptor open to a directory,
10654 and path should be relative; path will then be relative to that directory.
10655 dir_fd may not be implemented on your platform.
10656 If it is unavailable, using it will raise a NotImplementedError.
10657 [clinic start generated code]*/
10658
10659 static PyObject *
10660 os_mknod_impl(PyObject *module, path_t *path, int mode, dev_t device,
10661 int dir_fd)
10662 /*[clinic end generated code: output=92e55d3ca8917461 input=ee44531551a4d83b]*/
10663 {
10664 int result;
10665 int async_err = 0;
10666
10667 do {
10668 Py_BEGIN_ALLOW_THREADS
10669 #ifdef HAVE_MKNODAT
10670 if (dir_fd != DEFAULT_DIR_FD)
10671 result = mknodat(dir_fd, path->narrow, mode, device);
10672 else
10673 #endif
10674 result = mknod(path->narrow, mode, device);
10675 Py_END_ALLOW_THREADS
10676 } while (result != 0 && errno == EINTR &&
10677 !(async_err = PyErr_CheckSignals()));
10678 if (result != 0)
10679 return (!async_err) ? posix_error() : NULL;
10680
10681 Py_RETURN_NONE;
10682 }
10683 #endif /* defined(HAVE_MKNOD) && defined(HAVE_MAKEDEV) */
10684
10685
10686 #ifdef HAVE_DEVICE_MACROS
10687 /*[clinic input]
10688 os.major -> unsigned_int
10689
10690 device: dev_t
10691 /
10692
10693 Extracts a device major number from a raw device number.
10694 [clinic start generated code]*/
10695
10696 static unsigned int
10697 os_major_impl(PyObject *module, dev_t device)
10698 /*[clinic end generated code: output=5b3b2589bafb498e input=1e16a4d30c4d4462]*/
10699 {
10700 return major(device);
10701 }
10702
10703
10704 /*[clinic input]
10705 os.minor -> unsigned_int
10706
10707 device: dev_t
10708 /
10709
10710 Extracts a device minor number from a raw device number.
10711 [clinic start generated code]*/
10712
10713 static unsigned int
10714 os_minor_impl(PyObject *module, dev_t device)
10715 /*[clinic end generated code: output=5e1a25e630b0157d input=0842c6d23f24c65e]*/
10716 {
10717 return minor(device);
10718 }
10719
10720
10721 /*[clinic input]
10722 os.makedev -> dev_t
10723
10724 major: int
10725 minor: int
10726 /
10727
10728 Composes a raw device number from the major and minor device numbers.
10729 [clinic start generated code]*/
10730
10731 static dev_t
10732 os_makedev_impl(PyObject *module, int major, int minor)
10733 /*[clinic end generated code: output=881aaa4aba6f6a52 input=4b9fd8fc73cbe48f]*/
10734 {
10735 return makedev(major, minor);
10736 }
10737 #endif /* HAVE_DEVICE_MACROS */
10738
10739
10740 #if defined HAVE_FTRUNCATE || defined MS_WINDOWS
10741 /*[clinic input]
10742 os.ftruncate
10743
10744 fd: int
10745 length: Py_off_t
10746 /
10747
10748 Truncate a file, specified by file descriptor, to a specific length.
10749 [clinic start generated code]*/
10750
10751 static PyObject *
10752 os_ftruncate_impl(PyObject *module, int fd, Py_off_t length)
10753 /*[clinic end generated code: output=fba15523721be7e4 input=63b43641e52818f2]*/
10754 {
10755 int result;
10756 int async_err = 0;
10757
10758 if (PySys_Audit("os.truncate", "in", fd, length) < 0) {
10759 return NULL;
10760 }
10761
10762 do {
10763 Py_BEGIN_ALLOW_THREADS
10764 _Py_BEGIN_SUPPRESS_IPH
10765 #ifdef MS_WINDOWS
10766 result = _chsize_s(fd, length);
10767 #else
10768 result = ftruncate(fd, length);
10769 #endif
10770 _Py_END_SUPPRESS_IPH
10771 Py_END_ALLOW_THREADS
10772 } while (result != 0 && errno == EINTR &&
10773 !(async_err = PyErr_CheckSignals()));
10774 if (result != 0)
10775 return (!async_err) ? posix_error() : NULL;
10776 Py_RETURN_NONE;
10777 }
10778 #endif /* HAVE_FTRUNCATE || MS_WINDOWS */
10779
10780
10781 #if defined HAVE_TRUNCATE || defined MS_WINDOWS
10782 /*[clinic input]
10783 os.truncate
10784 path: path_t(allow_fd='PATH_HAVE_FTRUNCATE')
10785 length: Py_off_t
10786
10787 Truncate a file, specified by path, to a specific length.
10788
10789 On some platforms, path may also be specified as an open file descriptor.
10790 If this functionality is unavailable, using it raises an exception.
10791 [clinic start generated code]*/
10792
10793 static PyObject *
10794 os_truncate_impl(PyObject *module, path_t *path, Py_off_t length)
10795 /*[clinic end generated code: output=43009c8df5c0a12b input=77229cf0b50a9b77]*/
10796 {
10797 int result;
10798 #ifdef MS_WINDOWS
10799 int fd;
10800 #endif
10801
10802 if (path->fd != -1)
10803 return os_ftruncate_impl(module, path->fd, length);
10804
10805 if (PySys_Audit("os.truncate", "On", path->object, length) < 0) {
10806 return NULL;
10807 }
10808
10809 Py_BEGIN_ALLOW_THREADS
10810 _Py_BEGIN_SUPPRESS_IPH
10811 #ifdef MS_WINDOWS
10812 fd = _wopen(path->wide, _O_WRONLY | _O_BINARY | _O_NOINHERIT);
10813 if (fd < 0)
10814 result = -1;
10815 else {
10816 result = _chsize_s(fd, length);
10817 close(fd);
10818 if (result < 0)
10819 errno = result;
10820 }
10821 #else
10822 result = truncate(path->narrow, length);
10823 #endif
10824 _Py_END_SUPPRESS_IPH
10825 Py_END_ALLOW_THREADS
10826 if (result < 0)
10827 return posix_path_error(path);
10828
10829 Py_RETURN_NONE;
10830 }
10831 #endif /* HAVE_TRUNCATE || MS_WINDOWS */
10832
10833
10834 /* Issue #22396: On 32-bit AIX platform, the prototypes of os.posix_fadvise()
10835 and os.posix_fallocate() in system headers are wrong if _LARGE_FILES is
10836 defined, which is the case in Python on AIX. AIX bug report:
10837 http://www-01.ibm.com/support/docview.wss?uid=isg1IV56170 */
10838 #if defined(_AIX) && defined(_LARGE_FILES) && !defined(__64BIT__)
10839 # define POSIX_FADVISE_AIX_BUG
10840 #endif
10841
10842
10843 #if defined(HAVE_POSIX_FALLOCATE) && !defined(POSIX_FADVISE_AIX_BUG)
10844 /*[clinic input]
10845 os.posix_fallocate
10846
10847 fd: int
10848 offset: Py_off_t
10849 length: Py_off_t
10850 /
10851
10852 Ensure a file has allocated at least a particular number of bytes on disk.
10853
10854 Ensure that the file specified by fd encompasses a range of bytes
10855 starting at offset bytes from the beginning and continuing for length bytes.
10856 [clinic start generated code]*/
10857
10858 static PyObject *
10859 os_posix_fallocate_impl(PyObject *module, int fd, Py_off_t offset,
10860 Py_off_t length)
10861 /*[clinic end generated code: output=73f107139564aa9d input=d7a2ef0ab2ca52fb]*/
10862 {
10863 int result;
10864 int async_err = 0;
10865
10866 do {
10867 Py_BEGIN_ALLOW_THREADS
10868 result = posix_fallocate(fd, offset, length);
10869 Py_END_ALLOW_THREADS
10870 } while (result == EINTR && !(async_err = PyErr_CheckSignals()));
10871
10872 if (result == 0)
10873 Py_RETURN_NONE;
10874
10875 if (async_err)
10876 return NULL;
10877
10878 errno = result;
10879 return posix_error();
10880 }
10881 #endif /* HAVE_POSIX_FALLOCATE) && !POSIX_FADVISE_AIX_BUG */
10882
10883
10884 #if defined(HAVE_POSIX_FADVISE) && !defined(POSIX_FADVISE_AIX_BUG)
10885 /*[clinic input]
10886 os.posix_fadvise
10887
10888 fd: int
10889 offset: Py_off_t
10890 length: Py_off_t
10891 advice: int
10892 /
10893
10894 Announce an intention to access data in a specific pattern.
10895
10896 Announce an intention to access data in a specific pattern, thus allowing
10897 the kernel to make optimizations.
10898 The advice applies to the region of the file specified by fd starting at
10899 offset and continuing for length bytes.
10900 advice is one of POSIX_FADV_NORMAL, POSIX_FADV_SEQUENTIAL,
10901 POSIX_FADV_RANDOM, POSIX_FADV_NOREUSE, POSIX_FADV_WILLNEED, or
10902 POSIX_FADV_DONTNEED.
10903 [clinic start generated code]*/
10904
10905 static PyObject *
10906 os_posix_fadvise_impl(PyObject *module, int fd, Py_off_t offset,
10907 Py_off_t length, int advice)
10908 /*[clinic end generated code: output=412ef4aa70c98642 input=0fbe554edc2f04b5]*/
10909 {
10910 int result;
10911 int async_err = 0;
10912
10913 do {
10914 Py_BEGIN_ALLOW_THREADS
10915 result = posix_fadvise(fd, offset, length, advice);
10916 Py_END_ALLOW_THREADS
10917 } while (result == EINTR && !(async_err = PyErr_CheckSignals()));
10918
10919 if (result == 0)
10920 Py_RETURN_NONE;
10921
10922 if (async_err)
10923 return NULL;
10924
10925 errno = result;
10926 return posix_error();
10927 }
10928 #endif /* HAVE_POSIX_FADVISE && !POSIX_FADVISE_AIX_BUG */
10929
10930
10931 #ifdef MS_WINDOWS
10932 static PyObject*
10933 win32_putenv(PyObject *name, PyObject *value)
10934 {
10935 /* Search from index 1 because on Windows starting '=' is allowed for
10936 defining hidden environment variables. */
10937 if (PyUnicode_GET_LENGTH(name) == 0 ||
10938 PyUnicode_FindChar(name, '=', 1, PyUnicode_GET_LENGTH(name), 1) != -1)
10939 {
10940 PyErr_SetString(PyExc_ValueError, "illegal environment variable name");
10941 return NULL;
10942 }
10943 PyObject *unicode;
10944 if (value != NULL) {
10945 unicode = PyUnicode_FromFormat("%U=%U", name, value);
10946 }
10947 else {
10948 unicode = PyUnicode_FromFormat("%U=", name);
10949 }
10950 if (unicode == NULL) {
10951 return NULL;
10952 }
10953
10954 Py_ssize_t size;
10955 /* PyUnicode_AsWideCharString() rejects embedded null characters */
10956 wchar_t *env = PyUnicode_AsWideCharString(unicode, &size);
10957 Py_DECREF(unicode);
10958
10959 if (env == NULL) {
10960 return NULL;
10961 }
10962 if (size > _MAX_ENV) {
10963 PyErr_Format(PyExc_ValueError,
10964 "the environment variable is longer than %u characters",
10965 _MAX_ENV);
10966 PyMem_Free(env);
10967 return NULL;
10968 }
10969
10970 /* _wputenv() and SetEnvironmentVariableW() update the environment in the
10971 Process Environment Block (PEB). _wputenv() also updates CRT 'environ'
10972 and '_wenviron' variables, whereas SetEnvironmentVariableW() does not.
10973
10974 Prefer _wputenv() to be compatible with C libraries using CRT
10975 variables and CRT functions using these variables (ex: getenv()). */
10976 int err = _wputenv(env);
10977 PyMem_Free(env);
10978
10979 if (err) {
10980 posix_error();
10981 return NULL;
10982 }
10983
10984 Py_RETURN_NONE;
10985 }
10986 #endif
10987
10988
10989 #ifdef MS_WINDOWS
10990 /*[clinic input]
10991 os.putenv
10992
10993 name: unicode
10994 value: unicode
10995 /
10996
10997 Change or add an environment variable.
10998 [clinic start generated code]*/
10999
11000 static PyObject *
11001 os_putenv_impl(PyObject *module, PyObject *name, PyObject *value)
11002 /*[clinic end generated code: output=d29a567d6b2327d2 input=ba586581c2e6105f]*/
11003 {
11004 if (PySys_Audit("os.putenv", "OO", name, value) < 0) {
11005 return NULL;
11006 }
11007 return win32_putenv(name, value);
11008 }
11009 #else
11010 /*[clinic input]
11011 os.putenv
11012
11013 name: FSConverter
11014 value: FSConverter
11015 /
11016
11017 Change or add an environment variable.
11018 [clinic start generated code]*/
11019
11020 static PyObject *
11021 135 os_putenv_impl(PyObject *module, PyObject *name, PyObject *value)
11022 /*[clinic end generated code: output=d29a567d6b2327d2 input=a97bc6152f688d31]*/
11023 {
11024 135 const char *name_string = PyBytes_AS_STRING(name);
11025 135 const char *value_string = PyBytes_AS_STRING(value);
11026
11027
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 135 times.
135 if (strchr(name_string, '=') != NULL) {
11028 PyErr_SetString(PyExc_ValueError, "illegal environment variable name");
11029 return NULL;
11030 }
11031
11032
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 135 times.
135 if (PySys_Audit("os.putenv", "OO", name, value) < 0) {
11033 return NULL;
11034 }
11035
11036
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 135 times.
135 if (setenv(name_string, value_string, 1)) {
11037 return posix_error();
11038 }
11039 135 Py_RETURN_NONE;
11040 }
11041 #endif /* !defined(MS_WINDOWS) */
11042
11043
11044 #ifdef MS_WINDOWS
11045 /*[clinic input]
11046 os.unsetenv
11047 name: unicode
11048 /
11049
11050 Delete an environment variable.
11051 [clinic start generated code]*/
11052
11053 static PyObject *
11054 os_unsetenv_impl(PyObject *module, PyObject *name)
11055 /*[clinic end generated code: output=54c4137ab1834f02 input=4d6a1747cc526d2f]*/
11056 {
11057 if (PySys_Audit("os.unsetenv", "(O)", name) < 0) {
11058 return NULL;
11059 }
11060 return win32_putenv(name, NULL);
11061 }
11062 #else
11063 /*[clinic input]
11064 os.unsetenv
11065 name: FSConverter
11066 /
11067
11068 Delete an environment variable.
11069 [clinic start generated code]*/
11070
11071 static PyObject *
11072 116 os_unsetenv_impl(PyObject *module, PyObject *name)
11073 /*[clinic end generated code: output=54c4137ab1834f02 input=2bb5288a599c7107]*/
11074 {
11075
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 116 times.
116 if (PySys_Audit("os.unsetenv", "(O)", name) < 0) {
11076 return NULL;
11077 }
11078 #ifdef HAVE_BROKEN_UNSETENV
11079 unsetenv(PyBytes_AS_STRING(name));
11080 #else
11081 116 int err = unsetenv(PyBytes_AS_STRING(name));
11082
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 116 times.
116 if (err) {
11083 return posix_error();
11084 }
11085 #endif
11086
11087 116 Py_RETURN_NONE;
11088 }
11089 #endif /* !MS_WINDOWS */
11090
11091
11092 /*[clinic input]
11093 os.strerror
11094
11095 code: int
11096 /
11097
11098 Translate an error code to a message string.
11099 [clinic start generated code]*/
11100
11101 static PyObject *
11102 os_strerror_impl(PyObject *module, int code)
11103 /*[clinic end generated code: output=baebf09fa02a78f2 input=75a8673d97915a91]*/
11104 {
11105 char *message = strerror(code);
11106 if (message == NULL) {
11107 PyErr_SetString(PyExc_ValueError,
11108 "strerror() argument out of range");
11109 return NULL;
11110 }
11111 return PyUnicode_DecodeLocale(message, "surrogateescape");
11112 }
11113
11114
11115 #ifdef HAVE_SYS_WAIT_H
11116 #ifdef WCOREDUMP
11117 /*[clinic input]
11118 os.WCOREDUMP -> bool
11119
11120 status: int
11121 /
11122
11123 Return True if the process returning status was dumped to a core file.
11124 [clinic start generated code]*/
11125
11126 static int
11127 os_WCOREDUMP_impl(PyObject *module, int status)
11128 /*[clinic end generated code: output=1a584b147b16bd18 input=8b05e7ab38528d04]*/
11129 {
11130 WAIT_TYPE wait_status;
11131 WAIT_STATUS_INT(wait_status) = status;
11132 return WCOREDUMP(wait_status);
11133 }
11134 #endif /* WCOREDUMP */
11135
11136
11137 #ifdef WIFCONTINUED
11138 /*[clinic input]
11139 os.WIFCONTINUED -> bool
11140
11141 status: int
11142
11143 Return True if a particular process was continued from a job control stop.
11144
11145 Return True if the process returning status was continued from a
11146 job control stop.
11147 [clinic start generated code]*/
11148
11149 static int
11150 os_WIFCONTINUED_impl(PyObject *module, int status)
11151 /*[clinic end generated code: output=1e35295d844364bd input=e777e7d38eb25bd9]*/
11152 {
11153 WAIT_TYPE wait_status;
11154 WAIT_STATUS_INT(wait_status) = status;
11155 return WIFCONTINUED(wait_status);
11156 }
11157 #endif /* WIFCONTINUED */
11158
11159
11160 #ifdef WIFSTOPPED
11161 /*[clinic input]
11162 os.WIFSTOPPED -> bool
11163
11164 status: int
11165
11166 Return True if the process returning status was stopped.
11167 [clinic start generated code]*/
11168
11169 static int
11170 6540 os_WIFSTOPPED_impl(PyObject *module, int status)
11171 /*[clinic end generated code: output=fdb57122a5c9b4cb input=043cb7f1289ef904]*/
11172 {
11173 WAIT_TYPE wait_status;
11174 6540 WAIT_STATUS_INT(wait_status) = status;
11175 6540 return WIFSTOPPED(wait_status);
11176 }
11177 #endif /* WIFSTOPPED */
11178
11179
11180 #ifdef WIFSIGNALED
11181 /*[clinic input]
11182 os.WIFSIGNALED -> bool
11183
11184 status: int
11185
11186 Return True if the process returning status was terminated by a signal.
11187 [clinic start generated code]*/
11188
11189 static int
11190 os_WIFSIGNALED_impl(PyObject *module, int status)
11191 /*[clinic end generated code: output=d1dde4dcc819a5f5 input=d55ba7cc9ce5dc43]*/
11192 {
11193 WAIT_TYPE wait_status;
11194 WAIT_STATUS_INT(wait_status) = status;
11195 return WIFSIGNALED(wait_status);
11196 }
11197 #endif /* WIFSIGNALED */
11198
11199
11200 #ifdef WIFEXITED
11201 /*[clinic input]
11202 os.WIFEXITED -> bool
11203
11204 status: int
11205
11206 Return True if the process returning status exited via the exit() system call.
11207 [clinic start generated code]*/
11208
11209 static int
11210 os_WIFEXITED_impl(PyObject *module, int status)
11211 /*[clinic end generated code: output=01c09d6ebfeea397 input=d63775a6791586c0]*/
11212 {
11213 WAIT_TYPE wait_status;
11214 WAIT_STATUS_INT(wait_status) = status;
11215 return WIFEXITED(wait_status);
11216 }
11217 #endif /* WIFEXITED */
11218
11219
11220 #ifdef WEXITSTATUS
11221 /*[clinic input]
11222 os.WEXITSTATUS -> int
11223
11224 status: int
11225
11226 Return the process return code from status.
11227 [clinic start generated code]*/
11228
11229 static int
11230 os_WEXITSTATUS_impl(PyObject *module, int status)
11231 /*[clinic end generated code: output=6e3efbba11f6488d input=e1fb4944e377585b]*/
11232 {
11233 WAIT_TYPE wait_status;
11234 WAIT_STATUS_INT(wait_status) = status;
11235 return WEXITSTATUS(wait_status);
11236 }
11237 #endif /* WEXITSTATUS */
11238
11239
11240 #ifdef WTERMSIG
11241 /*[clinic input]
11242 os.WTERMSIG -> int
11243
11244 status: int
11245
11246 Return the signal that terminated the process that provided the status value.
11247 [clinic start generated code]*/
11248
11249 static int
11250 os_WTERMSIG_impl(PyObject *module, int status)
11251 /*[clinic end generated code: output=172f7dfc8dcfc3ad input=727fd7f84ec3f243]*/
11252 {
11253 WAIT_TYPE wait_status;
11254 WAIT_STATUS_INT(wait_status) = status;
11255 return WTERMSIG(wait_status);
11256 }
11257 #endif /* WTERMSIG */
11258
11259
11260 #ifdef WSTOPSIG
11261 /*[clinic input]
11262 os.WSTOPSIG -> int
11263
11264 status: int
11265
11266 Return the signal that stopped the process that provided the status value.
11267 [clinic start generated code]*/
11268
11269 static int
11270 os_WSTOPSIG_impl(PyObject *module, int status)
11271 /*[clinic end generated code: output=0ab7586396f5d82b input=46ebf1d1b293c5c1]*/
11272 {
11273 WAIT_TYPE wait_status;
11274 WAIT_STATUS_INT(wait_status) = status;
11275 return WSTOPSIG(wait_status);
11276 }
11277 #endif /* WSTOPSIG */
11278 #endif /* HAVE_SYS_WAIT_H */
11279
11280
11281 #if defined(HAVE_FSTATVFS) && defined(HAVE_SYS_STATVFS_H)
11282 #ifdef _SCO_DS
11283 /* SCO OpenServer 5.0 and later requires _SVID3 before it reveals the
11284 needed definitions in sys/statvfs.h */
11285 #define _SVID3
11286 #endif
11287 #include <sys/statvfs.h>
11288
11289 static PyObject*
11290 _pystatvfs_fromstructstatvfs(PyObject *module, struct statvfs st) {
11291 PyObject *StatVFSResultType = get_posix_state(module)->StatVFSResultType;
11292 PyObject *v = PyStructSequence_New((PyTypeObject *)StatVFSResultType);
11293 if (v == NULL)
11294 return NULL;
11295
11296 #if !defined(HAVE_LARGEFILE_SUPPORT)
11297 PyStructSequence_SET_ITEM(v, 0, PyLong_FromLong((long) st.f_bsize));
11298 PyStructSequence_SET_ITEM(v, 1, PyLong_FromLong((long) st.f_frsize));
11299 PyStructSequence_SET_ITEM(v, 2, PyLong_FromLong((long) st.f_blocks));
11300 PyStructSequence_SET_ITEM(v, 3, PyLong_FromLong((long) st.f_bfree));
11301 PyStructSequence_SET_ITEM(v, 4, PyLong_FromLong((long) st.f_bavail));
11302 PyStructSequence_SET_ITEM(v, 5, PyLong_FromLong((long) st.f_files));
11303 PyStructSequence_SET_ITEM(v, 6, PyLong_FromLong((long) st.f_ffree));
11304 PyStructSequence_SET_ITEM(v, 7, PyLong_FromLong((long) st.f_favail));
11305 PyStructSequence_SET_ITEM(v, 8, PyLong_FromLong((long) st.f_flag));
11306 PyStructSequence_SET_ITEM(v, 9, PyLong_FromLong((long) st.f_namemax));
11307 #else
11308 PyStructSequence_SET_ITEM(v, 0, PyLong_FromLong((long) st.f_bsize));
11309 PyStructSequence_SET_ITEM(v, 1, PyLong_FromLong((long) st.f_frsize));
11310 PyStructSequence_SET_ITEM(v, 2,
11311 PyLong_FromLongLong((long long) st.f_blocks));
11312 PyStructSequence_SET_ITEM(v, 3,
11313 PyLong_FromLongLong((long long) st.f_bfree));
11314 PyStructSequence_SET_ITEM(v, 4,
11315 PyLong_FromLongLong((long long) st.f_bavail));
11316 PyStructSequence_SET_ITEM(v, 5,
11317 PyLong_FromLongLong((long long) st.f_files));
11318 PyStructSequence_SET_ITEM(v, 6,
11319 PyLong_FromLongLong((long long) st.f_ffree));
11320 PyStructSequence_SET_ITEM(v, 7,
11321 PyLong_FromLongLong((long long) st.f_favail));
11322 PyStructSequence_SET_ITEM(v, 8, PyLong_FromLong((long) st.f_flag));
11323 PyStructSequence_SET_ITEM(v, 9, PyLong_FromLong((long) st.f_namemax));
11324 #endif
11325 /* The _ALL_SOURCE feature test macro defines f_fsid as a structure
11326 * (issue #32390). */
11327 #if defined(_AIX) && defined(_ALL_SOURCE)
11328 PyStructSequence_SET_ITEM(v, 10, PyLong_FromUnsignedLong(st.f_fsid.val[0]));
11329 #else
11330 PyStructSequence_SET_ITEM(v, 10, PyLong_FromUnsignedLong(st.f_fsid));
11331 #endif
11332 if (PyErr_Occurred()) {
11333 Py_DECREF(v);
11334 return NULL;
11335 }
11336
11337 return v;
11338 }
11339
11340
11341 /*[clinic input]
11342 os.fstatvfs
11343 fd: int
11344 /
11345
11346 Perform an fstatvfs system call on the given fd.
11347
11348 Equivalent to statvfs(fd).
11349 [clinic start generated code]*/
11350
11351 static PyObject *
11352 os_fstatvfs_impl(PyObject *module, int fd)
11353 /*[clinic end generated code: output=53547cf0cc55e6c5 input=d8122243ac50975e]*/
11354 {
11355 int result;
11356 int async_err = 0;
11357 struct statvfs st;
11358
11359 do {
11360 Py_BEGIN_ALLOW_THREADS
11361 result = fstatvfs(fd, &st);
11362 Py_END_ALLOW_THREADS
11363 } while (result != 0 && errno == EINTR &&
11364 !(async_err = PyErr_CheckSignals()));
11365 if (result != 0)
11366 return (!async_err) ? posix_error() : NULL;
11367
11368 return _pystatvfs_fromstructstatvfs(module, st);
11369 }
11370 #endif /* defined(HAVE_FSTATVFS) && defined(HAVE_SYS_STATVFS_H) */
11371
11372
11373 #if defined(HAVE_STATVFS) && defined(HAVE_SYS_STATVFS_H)
11374 #include <sys/statvfs.h>
11375 /*[clinic input]
11376 os.statvfs
11377
11378 path: path_t(allow_fd='PATH_HAVE_FSTATVFS')
11379
11380 Perform a statvfs system call on the given path.
11381
11382 path may always be specified as a string.
11383 On some platforms, path may also be specified as an open file descriptor.
11384 If this functionality is unavailable, using it raises an exception.
11385 [clinic start generated code]*/
11386
11387 static PyObject *
11388 os_statvfs_impl(PyObject *module, path_t *path)
11389 /*[clinic end generated code: output=87106dd1beb8556e input=3f5c35791c669bd9]*/
11390 {
11391 int result;
11392 struct statvfs st;
11393
11394 Py_BEGIN_ALLOW_THREADS
11395 #ifdef HAVE_FSTATVFS
11396 if (path->fd != -1) {
11397 result = fstatvfs(path->fd, &st);
11398 }
11399 else
11400 #endif
11401 result = statvfs(path->narrow, &st);
11402 Py_END_ALLOW_THREADS
11403
11404 if (result) {
11405 return path_error(path);
11406 }
11407
11408 return _pystatvfs_fromstructstatvfs(module, st);
11409 }
11410 #endif /* defined(HAVE_STATVFS) && defined(HAVE_SYS_STATVFS_H) */
11411
11412
11413 #ifdef MS_WINDOWS
11414 /*[clinic input]
11415 os._getdiskusage
11416
11417 path: path_t
11418
11419 Return disk usage statistics about the given path as a (total, free) tuple.
11420 [clinic start generated code]*/
11421
11422 static PyObject *
11423 os__getdiskusage_impl(PyObject *module, path_t *path)
11424 /*[clinic end generated code: output=3bd3991f5e5c5dfb input=6af8d1b7781cc042]*/
11425 {
11426 BOOL retval;
11427 ULARGE_INTEGER _, total, free;
11428 DWORD err = 0;
11429
11430 Py_BEGIN_ALLOW_THREADS
11431 retval = GetDiskFreeSpaceExW(path->wide, &_, &total, &free);
11432 Py_END_ALLOW_THREADS
11433 if (retval == 0) {
11434 if (GetLastError() == ERROR_DIRECTORY) {
11435 wchar_t *dir_path = NULL;
11436
11437 dir_path = PyMem_New(wchar_t, path->length + 1);
11438 if (dir_path == NULL) {
11439 return PyErr_NoMemory();
11440 }
11441
11442 wcscpy_s(dir_path, path->length + 1, path->wide);
11443
11444 if (_dirnameW(dir_path) != -1) {
11445 Py_BEGIN_ALLOW_THREADS
11446 retval = GetDiskFreeSpaceExW(dir_path, &_, &total, &free);
11447 Py_END_ALLOW_THREADS
11448 }
11449 /* Record the last error in case it's modified by PyMem_Free. */
11450 err = GetLastError();
11451 PyMem_Free(dir_path);
11452 if (retval) {
11453 goto success;
11454 }
11455 }
11456 return PyErr_SetFromWindowsErr(err);
11457 }
11458
11459 success:
11460 return Py_BuildValue("(LL)", total.QuadPart, free.QuadPart);
11461 }
11462 #endif /* MS_WINDOWS */
11463
11464
11465 /* This is used for fpathconf(), pathconf(), confstr() and sysconf().
11466 * It maps strings representing configuration variable names to
11467 * integer values, allowing those functions to be called with the
11468 * magic names instead of polluting the module's namespace with tons of
11469 * rarely-used constants. There are three separate tables that use
11470 * these definitions.
11471 *
11472 * This code is always included, even if none of the interfaces that
11473 * need it are included. The #if hackery needed to avoid it would be
11474 * sufficiently pervasive that it's not worth the loss of readability.
11475 */
11476 struct constdef {
11477 const char *name;
11478 int value;
11479 };
11480
11481 static int
11482 7216 conv_confname(PyObject *arg, int *valuep, struct constdef *table,
11483 size_t tablesize)
11484 {
11485
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 7216 times.
7216 if (PyLong_Check(arg)) {
11486 int value = _PyLong_AsInt(arg);
11487 if (value == -1 && PyErr_Occurred())
11488 return 0;
11489 *valuep = value;
11490 return 1;
11491 }
11492 else {
11493 /* look up the value in the table using a binary search */
11494 7216 size_t lo = 0;
11495 size_t mid;
11496 7216 size_t hi = tablesize;
11497 int cmp;
11498 const char *confname;
11499
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 7216 times.
7216 if (!PyUnicode_Check(arg)) {
11500 PyErr_SetString(PyExc_TypeError,
11501 "configuration names must be strings or integers");
11502 return 0;
11503 }
11504 7216 confname = PyUnicode_AsUTF8(arg);
11505
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7216 times.
7216 if (confname == NULL)
11506 return 0;
11507
1/2
✓ Branch 0 taken 40730 times.
✗ Branch 1 not taken.
40730 while (lo < hi) {
11508 40730 mid = (lo + hi) / 2;
11509 40730 cmp = strcmp(confname, table[mid].name);
11510
2/2
✓ Branch 0 taken 25840 times.
✓ Branch 1 taken 14890 times.
40730 if (cmp < 0)
11511 25840 hi = mid;
11512
2/2
✓ Branch 0 taken 7674 times.
✓ Branch 1 taken 7216 times.
14890 else if (cmp > 0)
11513 7674 lo = mid + 1;
11514 else {
11515 7216 *valuep = table[mid].value;
11516 7216 return 1;
11517 }
11518 }
11519 PyErr_SetString(PyExc_ValueError, "unrecognized configuration name");
11520 return 0;
11521 }
11522 }
11523
11524
11525 #if defined(HAVE_FPATHCONF) || defined(HAVE_PATHCONF)
11526 static struct constdef posix_constants_pathconf[] = {
11527 #ifdef _PC_ABI_AIO_XFER_MAX
11528 {"PC_ABI_AIO_XFER_MAX", _PC_ABI_AIO_XFER_MAX},
11529 #endif
11530 #ifdef _PC_ABI_ASYNC_IO
11531 {"PC_ABI_ASYNC_IO", _PC_ABI_ASYNC_IO},
11532 #endif
11533 #ifdef _PC_ASYNC_IO
11534 {"PC_ASYNC_IO", _PC_ASYNC_IO},
11535 #endif
11536 #ifdef _PC_CHOWN_RESTRICTED
11537 {"PC_CHOWN_RESTRICTED", _PC_CHOWN_RESTRICTED},
11538 #endif
11539 #ifdef _PC_FILESIZEBITS
11540 {"PC_FILESIZEBITS", _PC_FILESIZEBITS},
11541 #endif
11542 #ifdef _PC_LAST
11543 {"PC_LAST", _PC_LAST},
11544 #endif
11545 #ifdef _PC_LINK_MAX
11546 {"PC_LINK_MAX", _PC_LINK_MAX},
11547 #endif
11548 #ifdef _PC_MAX_CANON
11549 {"PC_MAX_CANON", _PC_MAX_CANON},
11550 #endif
11551 #ifdef _PC_MAX_INPUT
11552 {"PC_MAX_INPUT", _PC_MAX_INPUT},
11553 #endif
11554 #ifdef _PC_NAME_MAX
11555 {"PC_NAME_MAX", _PC_NAME_MAX},
11556 #endif
11557 #ifdef _PC_NO_TRUNC
11558 {"PC_NO_TRUNC", _PC_NO_TRUNC},
11559 #endif
11560 #ifdef _PC_PATH_MAX
11561 {"PC_PATH_MAX", _PC_PATH_MAX},
11562 #endif
11563 #ifdef _PC_PIPE_BUF
11564 {"PC_PIPE_BUF", _PC_PIPE_BUF},
11565 #endif
11566 #ifdef _PC_PRIO_IO
11567 {"PC_PRIO_IO", _PC_PRIO_IO},
11568 #endif
11569 #ifdef _PC_SOCK_MAXBUF
11570 {"PC_SOCK_MAXBUF", _PC_SOCK_MAXBUF},
11571 #endif
11572 #ifdef _PC_SYNC_IO
11573 {"PC_SYNC_IO", _PC_SYNC_IO},
11574 #endif
11575 #ifdef _PC_VDISABLE
11576 {"PC_VDISABLE", _PC_VDISABLE},
11577 #endif
11578 #ifdef _PC_ACL_ENABLED
11579 {"PC_ACL_ENABLED", _PC_ACL_ENABLED},
11580 #endif
11581 #ifdef _PC_MIN_HOLE_SIZE
11582 {"PC_MIN_HOLE_SIZE", _PC_MIN_HOLE_SIZE},
11583 #endif
11584 #ifdef _PC_ALLOC_SIZE_MIN
11585 {"PC_ALLOC_SIZE_MIN", _PC_ALLOC_SIZE_MIN},
11586 #endif
11587 #ifdef _PC_REC_INCR_XFER_SIZE
11588 {"PC_REC_INCR_XFER_SIZE", _PC_REC_INCR_XFER_SIZE},
11589 #endif
11590 #ifdef _PC_REC_MAX_XFER_SIZE
11591 {"PC_REC_MAX_XFER_SIZE", _PC_REC_MAX_XFER_SIZE},
11592 #endif
11593 #ifdef _PC_REC_MIN_XFER_SIZE
11594 {"PC_REC_MIN_XFER_SIZE", _PC_REC_MIN_XFER_SIZE},
11595 #endif
11596 #ifdef _PC_REC_XFER_ALIGN
11597 {"PC_REC_XFER_ALIGN", _PC_REC_XFER_ALIGN},
11598 #endif
11599 #ifdef _PC_SYMLINK_MAX
11600 {"PC_SYMLINK_MAX", _PC_SYMLINK_MAX},
11601 #endif
11602 #ifdef _PC_XATTR_ENABLED
11603 {"PC_XATTR_ENABLED", _PC_XATTR_ENABLED},
11604 #endif
11605 #ifdef _PC_XATTR_EXISTS
11606 {"PC_XATTR_EXISTS", _PC_XATTR_EXISTS},
11607 #endif
11608 #ifdef _PC_TIMESTAMP_RESOLUTION
11609 {"PC_TIMESTAMP_RESOLUTION", _PC_TIMESTAMP_RESOLUTION},
11610 #endif
11611 };
11612
11613 static int
11614 conv_path_confname(PyObject *arg, int *valuep)
11615 {
11616 return conv_confname(arg, valuep, posix_constants_pathconf,
11617 sizeof(posix_constants_pathconf)
11618 / sizeof(struct constdef));
11619 }
11620 #endif
11621
11622
11623 #ifdef HAVE_FPATHCONF
11624 /*[clinic input]
11625 os.fpathconf -> long
11626
11627 fd: fildes
11628 name: path_confname
11629 /
11630
11631 Return the configuration limit name for the file descriptor fd.
11632
11633 If there is no limit, return -1.
11634 [clinic start generated code]*/
11635
11636 static long
11637 os_fpathconf_impl(PyObject *module, int fd, int name)
11638 /*[clinic end generated code: output=d5b7042425fc3e21 input=5b8d2471cfaae186]*/
11639 {
11640 long limit;
11641
11642 errno = 0;
11643 limit = fpathconf(fd, name);
11644 if (limit == -1 && errno != 0)
11645 posix_error();
11646
11647 return limit;
11648 }
11649 #endif /* HAVE_FPATHCONF */
11650
11651
11652 #ifdef HAVE_PATHCONF
11653 /*[clinic input]
11654 os.pathconf -> long
11655 path: path_t(allow_fd='PATH_HAVE_FPATHCONF')
11656 name: path_confname
11657
11658 Return the configuration limit name for the file or directory path.
11659
11660 If there is no limit, return -1.
11661 On some platforms, path may also be specified as an open file descriptor.
11662 If this functionality is unavailable, using it raises an exception.
11663 [clinic start generated code]*/
11664
11665 static long
11666 os_pathconf_impl(PyObject *module, path_t *path, int name)
11667 /*[clinic end generated code: output=5bedee35b293a089 input=bc3e2a985af27e5e]*/
11668 {
11669 long limit;
11670
11671 errno = 0;
11672 #ifdef HAVE_FPATHCONF
11673 if (path->fd != -1)
11674 limit = fpathconf(path->fd, name);
11675 else
11676 #endif
11677 limit = pathconf(path->narrow, name);
11678 if (limit == -1 && errno != 0) {
11679 if (errno == EINVAL)
11680 /* could be a path or name problem */
11681 posix_error();
11682 else
11683 path_error(path);
11684 }
11685
11686 return limit;
11687 }
11688 #endif /* HAVE_PATHCONF */
11689
11690 #ifdef HAVE_CONFSTR
11691 static struct constdef posix_constants_confstr[] = {
11692 #ifdef _CS_ARCHITECTURE
11693 {"CS_ARCHITECTURE", _CS_ARCHITECTURE},
11694 #endif
11695 #ifdef _CS_GNU_LIBC_VERSION
11696 {"CS_GNU_LIBC_VERSION", _CS_GNU_LIBC_VERSION},
11697 #endif
11698 #ifdef _CS_GNU_LIBPTHREAD_VERSION
11699 {"CS_GNU_LIBPTHREAD_VERSION", _CS_GNU_LIBPTHREAD_VERSION},
11700 #endif
11701 #ifdef _CS_HOSTNAME
11702 {"CS_HOSTNAME", _CS_HOSTNAME},
11703 #endif
11704 #ifdef _CS_HW_PROVIDER
11705 {"CS_HW_PROVIDER", _CS_HW_PROVIDER},
11706 #endif
11707 #ifdef _CS_HW_SERIAL
11708 {"CS_HW_SERIAL", _CS_HW_SERIAL},
11709 #endif
11710 #ifdef _CS_INITTAB_NAME
11711 {"CS_INITTAB_NAME", _CS_INITTAB_NAME},
11712 #endif
11713 #ifdef _CS_LFS64_CFLAGS
11714 {"CS_LFS64_CFLAGS", _CS_LFS64_CFLAGS},
11715 #endif
11716 #ifdef _CS_LFS64_LDFLAGS
11717 {"CS_LFS64_LDFLAGS", _CS_LFS64_LDFLAGS},
11718 #endif
11719 #ifdef _CS_LFS64_LIBS
11720 {"CS_LFS64_LIBS", _CS_LFS64_LIBS},
11721 #endif
11722 #ifdef _CS_LFS64_LINTFLAGS
11723 {"CS_LFS64_LINTFLAGS", _CS_LFS64_LINTFLAGS},
11724 #endif
11725 #ifdef _CS_LFS_CFLAGS
11726 {"CS_LFS_CFLAGS", _CS_LFS_CFLAGS},
11727 #endif
11728 #ifdef _CS_LFS_LDFLAGS
11729 {"CS_LFS_LDFLAGS", _CS_LFS_LDFLAGS},
11730 #endif
11731 #ifdef _CS_LFS_LIBS
11732 {"CS_LFS_LIBS", _CS_LFS_LIBS},
11733 #endif
11734 #ifdef _CS_LFS_LINTFLAGS
11735 {"CS_LFS_LINTFLAGS", _CS_LFS_LINTFLAGS},
11736 #endif
11737 #ifdef _CS_MACHINE
11738 {"CS_MACHINE", _CS_MACHINE},
11739 #endif
11740 #ifdef _CS_PATH
11741 {"CS_PATH", _CS_PATH},
11742 #endif
11743 #ifdef _CS_RELEASE
11744 {"CS_RELEASE", _CS_RELEASE},
11745 #endif
11746 #ifdef _CS_SRPC_DOMAIN
11747 {"CS_SRPC_DOMAIN", _CS_SRPC_DOMAIN},
11748 #endif
11749 #ifdef _CS_SYSNAME
11750 {"CS_SYSNAME", _CS_SYSNAME},
11751 #endif
11752 #ifdef _CS_VERSION
11753 {"CS_VERSION", _CS_VERSION},
11754 #endif
11755 #ifdef _CS_XBS5_ILP32_OFF32_CFLAGS
11756 {"CS_XBS5_ILP32_OFF32_CFLAGS", _CS_XBS5_ILP32_OFF32_CFLAGS},
11757 #endif
11758 #ifdef _CS_XBS5_ILP32_OFF32_LDFLAGS
11759 {"CS_XBS5_ILP32_OFF32_LDFLAGS", _CS_XBS5_ILP32_OFF32_LDFLAGS},
11760 #endif
11761 #ifdef _CS_XBS5_ILP32_OFF32_LIBS
11762 {"CS_XBS5_ILP32_OFF32_LIBS", _CS_XBS5_ILP32_OFF32_LIBS},
11763 #endif
11764 #ifdef _CS_XBS5_ILP32_OFF32_LINTFLAGS
11765 {"CS_XBS5_ILP32_OFF32_LINTFLAGS", _CS_XBS5_ILP32_OFF32_LINTFLAGS},
11766 #endif
11767 #ifdef _CS_XBS5_ILP32_OFFBIG_CFLAGS
11768 {"CS_XBS5_ILP32_OFFBIG_CFLAGS", _CS_XBS5_ILP32_OFFBIG_CFLAGS},
11769 #endif
11770 #ifdef _CS_XBS5_ILP32_OFFBIG_LDFLAGS
11771 {"CS_XBS5_ILP32_OFFBIG_LDFLAGS", _CS_XBS5_ILP32_OFFBIG_LDFLAGS},
11772 #endif
11773 #ifdef _CS_XBS5_ILP32_OFFBIG_LIBS
11774 {"CS_XBS5_ILP32_OFFBIG_LIBS", _CS_XBS5_ILP32_OFFBIG_LIBS},
11775 #endif
11776 #ifdef _CS_XBS5_ILP32_OFFBIG_LINTFLAGS
11777 {"CS_XBS5_ILP32_OFFBIG_LINTFLAGS", _CS_XBS5_ILP32_OFFBIG_LINTFLAGS},
11778 #endif
11779 #ifdef _CS_XBS5_LP64_OFF64_CFLAGS
11780 {"CS_XBS5_LP64_OFF64_CFLAGS", _CS_XBS5_LP64_OFF64_CFLAGS},
11781 #endif
11782 #ifdef _CS_XBS5_LP64_OFF64_LDFLAGS
11783 {"CS_XBS5_LP64_OFF64_LDFLAGS", _CS_XBS5_LP64_OFF64_LDFLAGS},
11784 #endif
11785 #ifdef _CS_XBS5_LP64_OFF64_LIBS
11786 {"CS_XBS5_LP64_OFF64_LIBS", _CS_XBS5_LP64_OFF64_LIBS},
11787 #endif
11788 #ifdef _CS_XBS5_LP64_OFF64_LINTFLAGS
11789 {"CS_XBS5_LP64_OFF64_LINTFLAGS", _CS_XBS5_LP64_OFF64_LINTFLAGS},
11790 #endif
11791 #ifdef _CS_XBS5_LPBIG_OFFBIG_CFLAGS
11792 {"CS_XBS5_LPBIG_OFFBIG_CFLAGS", _CS_XBS5_LPBIG_OFFBIG_CFLAGS},
11793 #endif
11794 #ifdef _CS_XBS5_LPBIG_OFFBIG_LDFLAGS
11795 {"CS_XBS5_LPBIG_OFFBIG_LDFLAGS", _CS_XBS5_LPBIG_OFFBIG_LDFLAGS},
11796 #endif
11797 #ifdef _CS_XBS5_LPBIG_OFFBIG_LIBS
11798 {"CS_XBS5_LPBIG_OFFBIG_LIBS", _CS_XBS5_LPBIG_OFFBIG_LIBS},
11799 #endif
11800 #ifdef _CS_XBS5_LPBIG_OFFBIG_LINTFLAGS
11801 {"CS_XBS5_LPBIG_OFFBIG_LINTFLAGS", _CS_XBS5_LPBIG_OFFBIG_LINTFLAGS},
11802 #endif
11803 #ifdef _MIPS_CS_AVAIL_PROCESSORS
11804 {"MIPS_CS_AVAIL_PROCESSORS", _MIPS_CS_AVAIL_PROCESSORS},
11805 #endif
11806 #ifdef _MIPS_CS_BASE
11807 {"MIPS_CS_BASE", _MIPS_CS_BASE},
11808 #endif
11809 #ifdef _MIPS_CS_HOSTID
11810 {"MIPS_CS_HOSTID", _MIPS_CS_HOSTID},
11811 #endif
11812 #ifdef _MIPS_CS_HW_NAME
11813 {"MIPS_CS_HW_NAME", _MIPS_CS_HW_NAME},
11814 #endif
11815 #ifdef _MIPS_CS_NUM_PROCESSORS
11816 {"MIPS_CS_NUM_PROCESSORS", _MIPS_CS_NUM_PROCESSORS},
11817 #endif
11818 #ifdef _MIPS_CS_OSREL_MAJ
11819 {"MIPS_CS_OSREL_MAJ", _MIPS_CS_OSREL_MAJ},
11820 #endif
11821 #ifdef _MIPS_CS_OSREL_MIN
11822 {"MIPS_CS_OSREL_MIN", _MIPS_CS_OSREL_MIN},
11823 #endif
11824 #ifdef _MIPS_CS_OSREL_PATCH
11825 {"MIPS_CS_OSREL_PATCH", _MIPS_CS_OSREL_PATCH},
11826 #endif
11827 #ifdef _MIPS_CS_OS_NAME
11828 {"MIPS_CS_OS_NAME", _MIPS_CS_OS_NAME},
11829 #endif
11830 #ifdef _MIPS_CS_OS_PROVIDER
11831 {"MIPS_CS_OS_PROVIDER", _MIPS_CS_OS_PROVIDER},
11832 #endif
11833 #ifdef _MIPS_CS_PROCESSORS
11834 {"MIPS_CS_PROCESSORS", _MIPS_CS_PROCESSORS},
11835 #endif
11836 #ifdef _MIPS_CS_SERIAL
11837 {"MIPS_CS_SERIAL", _MIPS_CS_SERIAL},
11838 #endif
11839 #ifdef _MIPS_CS_VENDOR
11840 {"MIPS_CS_VENDOR", _MIPS_CS_VENDOR},
11841 #endif
11842 };
11843
11844 static int
11845 4135 conv_confstr_confname(PyObject *arg, int *valuep)
11846 {
11847 4135 return conv_confname(arg, valuep, posix_constants_confstr,
11848 sizeof(posix_constants_confstr)
11849 / sizeof(struct constdef));
11850 }
11851
11852
11853 /*[clinic input]
11854 os.confstr
11855
11856 name: confstr_confname
11857 /
11858
11859 Return a string-valued system configuration variable.
11860 [clinic start generated code]*/
11861
11862 static PyObject *
11863 4135 os_confstr_impl(PyObject *module, int name)
11864 /*[clinic end generated code: output=bfb0b1b1e49b9383 input=18fb4d0567242e65]*/
11865 {
11866 4135 PyObject *result = NULL;
11867 char buffer[255];
11868 size_t len;
11869
11870 4135 errno = 0;
11871 4135 len = confstr(name, buffer, sizeof(buffer));
11872
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4135 times.
4135 if (len == 0) {
11873 if (errno) {
11874 posix_error();
11875 return NULL;
11876 }
11877 else {
11878 Py_RETURN_NONE;
11879 }
11880 }
11881
11882
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4135 times.
4135 if (len >= sizeof(buffer)) {
11883 size_t len2;
11884 char *buf = PyMem_Malloc(len);
11885 if (buf == NULL)
11886 return PyErr_NoMemory();
11887 len2 = confstr(name, buf, len);
11888 assert(len == len2);
11889 result = PyUnicode_DecodeFSDefaultAndSize(buf, len2-1);
11890 PyMem_Free(buf);
11891 }
11892 else
11893 4135 result = PyUnicode_DecodeFSDefaultAndSize(buffer, len-1);
11894 4135 return result;
11895 }
11896 #endif /* HAVE_CONFSTR */
11897
11898
11899 #ifdef HAVE_SYSCONF
11900 static struct constdef posix_constants_sysconf[] = {
11901 #ifdef _SC_2_CHAR_TERM
11902 {"SC_2_CHAR_TERM", _SC_2_CHAR_TERM},
11903 #endif
11904 #ifdef _SC_2_C_BIND
11905 {"SC_2_C_BIND", _SC_2_C_BIND},
11906 #endif
11907 #ifdef _SC_2_C_DEV
11908 {"SC_2_C_DEV", _SC_2_C_DEV},
11909 #endif
11910 #ifdef _SC_2_C_VERSION
11911 {"SC_2_C_VERSION", _SC_2_C_VERSION},
11912 #endif
11913 #ifdef _SC_2_FORT_DEV
11914 {"SC_2_FORT_DEV", _SC_2_FORT_DEV},
11915 #endif
11916 #ifdef _SC_2_FORT_RUN
11917 {"SC_2_FORT_RUN", _SC_2_FORT_RUN},
11918 #endif
11919 #ifdef _SC_2_LOCALEDEF
11920 {"SC_2_LOCALEDEF", _SC_2_LOCALEDEF},
11921 #endif
11922 #ifdef _SC_2_SW_DEV
11923 {"SC_2_SW_DEV", _SC_2_SW_DEV},
11924 #endif
11925 #ifdef _SC_2_UPE
11926 {"SC_2_UPE", _SC_2_UPE},
11927 #endif
11928 #ifdef _SC_2_VERSION
11929 {"SC_2_VERSION", _SC_2_VERSION},
11930 #endif
11931 #ifdef _SC_ABI_ASYNCHRONOUS_IO
11932 {"SC_ABI_ASYNCHRONOUS_IO", _SC_ABI_ASYNCHRONOUS_IO},
11933 #endif
11934 #ifdef _SC_ACL
11935 {"SC_ACL", _SC_ACL},
11936 #endif
11937 #ifdef _SC_AIO_LISTIO_MAX
11938 {"SC_AIO_LISTIO_MAX", _SC_AIO_LISTIO_MAX},
11939 #endif
11940 #ifdef _SC_AIO_MAX
11941 {"SC_AIO_MAX", _SC_AIO_MAX},
11942 #endif
11943 #ifdef _SC_AIO_PRIO_DELTA_MAX
11944 {"SC_AIO_PRIO_DELTA_MAX", _SC_AIO_PRIO_DELTA_MAX},
11945 #endif
11946 #ifdef _SC_ARG_MAX
11947 {"SC_ARG_MAX", _SC_ARG_MAX},
11948 #endif
11949 #ifdef _SC_ASYNCHRONOUS_IO
11950 {"SC_ASYNCHRONOUS_IO", _SC_ASYNCHRONOUS_IO},
11951 #endif
11952 #ifdef _SC_ATEXIT_MAX
11953 {"SC_ATEXIT_MAX", _SC_ATEXIT_MAX},
11954 #endif
11955 #ifdef _SC_AUDIT
11956 {"SC_AUDIT", _SC_AUDIT},
11957 #endif
11958 #ifdef _SC_AVPHYS_PAGES
11959 {"SC_AVPHYS_PAGES", _SC_AVPHYS_PAGES},
11960 #endif
11961 #ifdef _SC_BC_BASE_MAX
11962 {"SC_BC_BASE_MAX", _SC_BC_BASE_MAX},
11963 #endif
11964 #ifdef _SC_BC_DIM_MAX
11965 {"SC_BC_DIM_MAX", _SC_BC_DIM_MAX},
11966 #endif
11967 #ifdef _SC_BC_SCALE_MAX
11968 {"SC_BC_SCALE_MAX", _SC_BC_SCALE_MAX},
11969 #endif
11970 #ifdef _SC_BC_STRING_MAX
11971 {"SC_BC_STRING_MAX", _SC_BC_STRING_MAX},
11972 #endif
11973 #ifdef _SC_CAP
11974 {"SC_CAP", _SC_CAP},
11975 #endif
11976 #ifdef _SC_CHARCLASS_NAME_MAX
11977 {"SC_CHARCLASS_NAME_MAX", _SC_CHARCLASS_NAME_MAX},
11978 #endif
11979 #ifdef _SC_CHAR_BIT
11980 {"SC_CHAR_BIT", _SC_CHAR_BIT},
11981 #endif
11982 #ifdef _SC_CHAR_MAX
11983 {"SC_CHAR_MAX", _SC_CHAR_MAX},
11984 #endif
11985 #ifdef _SC_CHAR_MIN
11986 {"SC_CHAR_MIN", _SC_CHAR_MIN},
11987 #endif
11988 #ifdef _SC_CHILD_MAX
11989 {"SC_CHILD_MAX", _SC_CHILD_MAX},
11990 #endif
11991 #ifdef _SC_CLK_TCK
11992 {"SC_CLK_TCK", _SC_CLK_TCK},
11993 #endif
11994 #ifdef _SC_COHER_BLKSZ
11995 {"SC_COHER_BLKSZ", _SC_COHER_BLKSZ},
11996 #endif
11997 #ifdef _SC_COLL_WEIGHTS_MAX
11998 {"SC_COLL_WEIGHTS_MAX", _SC_COLL_WEIGHTS_MAX},
11999 #endif
12000 #ifdef _SC_DCACHE_ASSOC
12001 {"SC_DCACHE_ASSOC", _SC_DCACHE_ASSOC},
12002 #endif
12003 #ifdef _SC_DCACHE_BLKSZ
12004 {"SC_DCACHE_BLKSZ", _SC_DCACHE_BLKSZ},
12005 #endif
12006 #ifdef _SC_DCACHE_LINESZ
12007 {"SC_DCACHE_LINESZ", _SC_DCACHE_LINESZ},
12008 #endif
12009 #ifdef _SC_DCACHE_SZ
12010 {"SC_DCACHE_SZ", _SC_DCACHE_SZ},
12011 #endif
12012 #ifdef _SC_DCACHE_TBLKSZ
12013 {"SC_DCACHE_TBLKSZ", _SC_DCACHE_TBLKSZ},
12014 #endif
12015 #ifdef _SC_DELAYTIMER_MAX
12016 {"SC_DELAYTIMER_MAX", _SC_DELAYTIMER_MAX},
12017 #endif
12018 #ifdef _SC_EQUIV_CLASS_MAX
12019 {"SC_EQUIV_CLASS_MAX", _SC_EQUIV_CLASS_MAX},
12020 #endif
12021 #ifdef _SC_EXPR_NEST_MAX
12022 {"SC_EXPR_NEST_MAX", _SC_EXPR_NEST_MAX},
12023 #endif
12024 #ifdef _SC_FSYNC
12025 {"SC_FSYNC", _SC_FSYNC},
12026 #endif
12027 #ifdef _SC_GETGR_R_SIZE_MAX
12028 {"SC_GETGR_R_SIZE_MAX", _SC_GETGR_R_SIZE_MAX},
12029 #endif
12030 #ifdef _SC_GETPW_R_SIZE_MAX
12031 {"SC_GETPW_R_SIZE_MAX", _SC_GETPW_R_SIZE_MAX},
12032 #endif
12033 #ifdef _SC_ICACHE_ASSOC
12034 {"SC_ICACHE_ASSOC", _SC_ICACHE_ASSOC},
12035 #endif
12036 #ifdef _SC_ICACHE_BLKSZ
12037 {"SC_ICACHE_BLKSZ", _SC_ICACHE_BLKSZ},
12038 #endif
12039 #ifdef _SC_ICACHE_LINESZ
12040 {"SC_ICACHE_LINESZ", _SC_ICACHE_LINESZ},
12041 #endif
12042 #ifdef _SC_ICACHE_SZ
12043 {"SC_ICACHE_SZ", _SC_ICACHE_SZ},
12044 #endif
12045 #ifdef _SC_INF
12046 {"SC_INF", _SC_INF},
12047 #endif
12048 #ifdef _SC_INT_MAX
12049 {"SC_INT_MAX", _SC_INT_MAX},
12050 #endif
12051 #ifdef _SC_INT_MIN
12052 {"SC_INT_MIN", _SC_INT_MIN},
12053 #endif
12054 #ifdef _SC_IOV_MAX
12055 {"SC_IOV_MAX", _SC_IOV_MAX},
12056 #endif
12057 #ifdef _SC_IP_SECOPTS
12058 {"SC_IP_SECOPTS", _SC_IP_SECOPTS},
12059 #endif
12060 #ifdef _SC_JOB_CONTROL
12061 {"SC_JOB_CONTROL", _SC_JOB_CONTROL},
12062 #endif
12063 #ifdef _SC_KERN_POINTERS
12064 {"SC_KERN_POINTERS", _SC_KERN_POINTERS},
12065 #endif
12066 #ifdef _SC_KERN_SIM
12067 {"SC_KERN_SIM", _SC_KERN_SIM},
12068 #endif
12069 #ifdef _SC_LINE_MAX
12070 {"SC_LINE_MAX", _SC_LINE_MAX},
12071 #endif
12072 #ifdef _SC_LOGIN_NAME_MAX
12073 {"SC_LOGIN_NAME_MAX", _SC_LOGIN_NAME_MAX},
12074 #endif
12075 #ifdef _SC_LOGNAME_MAX
12076 {"SC_LOGNAME_MAX", _SC_LOGNAME_MAX},
12077 #endif
12078 #ifdef _SC_LONG_BIT
12079 {"SC_LONG_BIT", _SC_LONG_BIT},
12080 #endif
12081 #ifdef _SC_MAC
12082 {"SC_MAC", _SC_MAC},
12083 #endif
12084 #ifdef _SC_MAPPED_FILES
12085 {"SC_MAPPED_FILES", _SC_MAPPED_FILES},
12086 #endif
12087 #ifdef _SC_MAXPID
12088 {"SC_MAXPID", _SC_MAXPID},
12089 #endif
12090 #ifdef _SC_MB_LEN_MAX
12091 {"SC_MB_LEN_MAX", _SC_MB_LEN_MAX},
12092 #endif
12093 #ifdef _SC_MEMLOCK
12094 {"SC_MEMLOCK", _SC_MEMLOCK},
12095 #endif
12096 #ifdef _SC_MEMLOCK_RANGE
12097 {"SC_MEMLOCK_RANGE", _SC_MEMLOCK_RANGE},
12098 #endif
12099 #ifdef _SC_MEMORY_PROTECTION
12100 {"SC_MEMORY_PROTECTION", _SC_MEMORY_PROTECTION},
12101 #endif
12102 #ifdef _SC_MESSAGE_PASSING
12103 {"SC_MESSAGE_PASSING", _SC_MESSAGE_PASSING},
12104 #endif
12105 #ifdef _SC_MMAP_FIXED_ALIGNMENT
12106 {"SC_MMAP_FIXED_ALIGNMENT", _SC_MMAP_FIXED_ALIGNMENT},
12107 #endif
12108 #ifdef _SC_MQ_OPEN_MAX
12109 {"SC_MQ_OPEN_MAX", _SC_MQ_OPEN_MAX},
12110 #endif
12111 #ifdef _SC_MQ_PRIO_MAX
12112 {"SC_MQ_PRIO_MAX", _SC_MQ_PRIO_MAX},
12113 #endif
12114 #ifdef _SC_NACLS_MAX
12115 {"SC_NACLS_MAX", _SC_NACLS_MAX},
12116 #endif
12117 #ifdef _SC_NGROUPS_MAX
12118 {"SC_NGROUPS_MAX", _SC_NGROUPS_MAX},
12119 #endif
12120 #ifdef _SC_NL_ARGMAX
12121 {"SC_NL_ARGMAX", _SC_NL_ARGMAX},
12122 #endif
12123 #ifdef _SC_NL_LANGMAX
12124 {"SC_NL_LANGMAX", _SC_NL_LANGMAX},
12125 #endif
12126 #ifdef _SC_NL_MSGMAX
12127 {"SC_NL_MSGMAX", _SC_NL_MSGMAX},
12128 #endif
12129 #ifdef _SC_NL_NMAX
12130 {"SC_NL_NMAX", _SC_NL_NMAX},
12131 #endif
12132 #ifdef _SC_NL_SETMAX
12133 {"SC_NL_SETMAX", _SC_NL_SETMAX},
12134 #endif
12135 #ifdef _SC_NL_TEXTMAX
12136 {"SC_NL_TEXTMAX", _SC_NL_TEXTMAX},
12137 #endif
12138 #ifdef _SC_NPROCESSORS_CONF
12139 {"SC_NPROCESSORS_CONF", _SC_NPROCESSORS_CONF},
12140 #endif
12141 #ifdef _SC_NPROCESSORS_ONLN
12142 {"SC_NPROCESSORS_ONLN", _SC_NPROCESSORS_ONLN},
12143 #endif
12144 #ifdef _SC_NPROC_CONF
12145 {"SC_NPROC_CONF", _SC_NPROC_CONF},
12146 #endif
12147 #ifdef _SC_NPROC_ONLN
12148 {"SC_NPROC_ONLN", _SC_NPROC_ONLN},
12149 #endif
12150 #ifdef _SC_NZERO
12151 {"SC_NZERO", _SC_NZERO},
12152 #endif
12153 #ifdef _SC_OPEN_MAX
12154 {"SC_OPEN_MAX", _SC_OPEN_MAX},
12155 #endif
12156 #ifdef _SC_PAGESIZE
12157 {"SC_PAGESIZE", _SC_PAGESIZE},
12158 #endif
12159 #ifdef _SC_PAGE_SIZE
12160 {"SC_PAGE_SIZE", _SC_PAGE_SIZE},
12161 #endif
12162 #ifdef _SC_AIX_REALMEM
12163 {"SC_AIX_REALMEM", _SC_AIX_REALMEM},
12164 #endif
12165 #ifdef _SC_PASS_MAX
12166 {"SC_PASS_MAX", _SC_PASS_MAX},
12167 #endif
12168 #ifdef _SC_PHYS_PAGES
12169 {"SC_PHYS_PAGES", _SC_PHYS_PAGES},
12170 #endif
12171 #ifdef _SC_PII
12172 {"SC_PII", _SC_PII},
12173 #endif
12174 #ifdef _SC_PII_INTERNET
12175 {"SC_PII_INTERNET", _SC_PII_INTERNET},
12176 #endif
12177 #ifdef _SC_PII_INTERNET_DGRAM
12178 {"SC_PII_INTERNET_DGRAM", _SC_PII_INTERNET_DGRAM},
12179 #endif
12180 #ifdef _SC_PII_INTERNET_STREAM
12181 {"SC_PII_INTERNET_STREAM", _SC_PII_INTERNET_STREAM},
12182 #endif
12183 #ifdef _SC_PII_OSI
12184 {"SC_PII_OSI", _SC_PII_OSI},
12185 #endif
12186 #ifdef _SC_PII_OSI_CLTS
12187 {"SC_PII_OSI_CLTS", _SC_PII_OSI_CLTS},
12188 #endif
12189 #ifdef _SC_PII_OSI_COTS
12190 {"SC_PII_OSI_COTS", _SC_PII_OSI_COTS},
12191 #endif
12192 #ifdef _SC_PII_OSI_M
12193 {"SC_PII_OSI_M", _SC_PII_OSI_M},
12194 #endif
12195 #ifdef _SC_PII_SOCKET
12196 {"SC_PII_SOCKET", _SC_PII_SOCKET},
12197 #endif
12198 #ifdef _SC_PII_XTI
12199 {"SC_PII_XTI", _SC_PII_XTI},
12200 #endif
12201 #ifdef _SC_POLL
12202 {"SC_POLL", _SC_POLL},
12203 #endif
12204 #ifdef _SC_PRIORITIZED_IO
12205 {"SC_PRIORITIZED_IO", _SC_PRIORITIZED_IO},
12206 #endif
12207 #ifdef _SC_PRIORITY_SCHEDULING
12208 {"SC_PRIORITY_SCHEDULING", _SC_PRIORITY_SCHEDULING},
12209 #endif
12210 #ifdef _SC_REALTIME_SIGNALS
12211 {"SC_REALTIME_SIGNALS", _SC_REALTIME_SIGNALS},
12212 #endif
12213 #ifdef _SC_RE_DUP_MAX
12214 {"SC_RE_DUP_MAX", _SC_RE_DUP_MAX},
12215 #endif
12216 #ifdef _SC_RTSIG_MAX
12217 {"SC_RTSIG_MAX", _SC_RTSIG_MAX},
12218 #endif
12219 #ifdef _SC_SAVED_IDS
12220 {"SC_SAVED_IDS", _SC_SAVED_IDS},
12221 #endif
12222 #ifdef _SC_SCHAR_MAX
12223 {"SC_SCHAR_MAX", _SC_SCHAR_MAX},
12224 #endif
12225 #ifdef _SC_SCHAR_MIN
12226 {"SC_SCHAR_MIN", _SC_SCHAR_MIN},
12227 #endif
12228 #ifdef _SC_SELECT
12229 {"SC_SELECT", _SC_SELECT},
12230 #endif
12231 #ifdef _SC_SEMAPHORES
12232 {"SC_SEMAPHORES", _SC_SEMAPHORES},
12233 #endif
12234 #ifdef _SC_SEM_NSEMS_MAX
12235 {"SC_SEM_NSEMS_MAX", _SC_SEM_NSEMS_MAX},
12236 #endif
12237 #ifdef _SC_SEM_VALUE_MAX
12238 {"SC_SEM_VALUE_MAX", _SC_SEM_VALUE_MAX},
12239 #endif
12240 #ifdef _SC_SHARED_MEMORY_OBJECTS
12241 {"SC_SHARED_MEMORY_OBJECTS", _SC_SHARED_MEMORY_OBJECTS},
12242 #endif
12243 #ifdef _SC_SHRT_MAX
12244 {"SC_SHRT_MAX", _SC_SHRT_MAX},
12245 #endif
12246 #ifdef _SC_SHRT_MIN
12247 {"SC_SHRT_MIN", _SC_SHRT_MIN},
12248 #endif
12249 #ifdef _SC_SIGQUEUE_MAX
12250 {"SC_SIGQUEUE_MAX", _SC_SIGQUEUE_MAX},
12251 #endif
12252 #ifdef _SC_SIGRT_MAX
12253 {"SC_SIGRT_MAX", _SC_SIGRT_MAX},
12254 #endif
12255 #ifdef _SC_SIGRT_MIN
12256 {"SC_SIGRT_MIN", _SC_SIGRT_MIN},
12257 #endif
12258 #ifdef _SC_SOFTPOWER
12259 {"SC_SOFTPOWER", _SC_SOFTPOWER},
12260 #endif
12261 #ifdef _SC_SPLIT_CACHE
12262 {"SC_SPLIT_CACHE", _SC_SPLIT_CACHE},
12263 #endif
12264 #ifdef _SC_SSIZE_MAX
12265 {"SC_SSIZE_MAX", _SC_SSIZE_MAX},
12266 #endif
12267 #ifdef _SC_STACK_PROT
12268 {"SC_STACK_PROT", _SC_STACK_PROT},
12269 #endif
12270 #ifdef _SC_STREAM_MAX
12271 {"SC_STREAM_MAX", _SC_STREAM_MAX},
12272 #endif
12273 #ifdef _SC_SYNCHRONIZED_IO
12274 {"SC_SYNCHRONIZED_IO", _SC_SYNCHRONIZED_IO},
12275 #endif
12276 #ifdef _SC_THREADS
12277 {"SC_THREADS", _SC_THREADS},
12278 #endif
12279 #ifdef _SC_THREAD_ATTR_STACKADDR
12280 {"SC_THREAD_ATTR_STACKADDR", _SC_THREAD_ATTR_STACKADDR},
12281 #endif
12282 #ifdef _SC_THREAD_ATTR_STACKSIZE
12283 {"SC_THREAD_ATTR_STACKSIZE", _SC_THREAD_ATTR_STACKSIZE},
12284 #endif
12285 #ifdef _SC_THREAD_DESTRUCTOR_ITERATIONS
12286 {"SC_THREAD_DESTRUCTOR_ITERATIONS", _SC_THREAD_DESTRUCTOR_ITERATIONS},
12287 #endif
12288 #ifdef _SC_THREAD_KEYS_MAX
12289 {"SC_THREAD_KEYS_MAX", _SC_THREAD_KEYS_MAX},
12290 #endif
12291 #ifdef _SC_THREAD_PRIORITY_SCHEDULING
12292 {"SC_THREAD_PRIORITY_SCHEDULING", _SC_THREAD_PRIORITY_SCHEDULING},
12293 #endif
12294 #ifdef _SC_THREAD_PRIO_INHERIT
12295 {"SC_THREAD_PRIO_INHERIT", _SC_THREAD_PRIO_INHERIT},
12296 #endif
12297 #ifdef _SC_THREAD_PRIO_PROTECT
12298 {"SC_THREAD_PRIO_PROTECT", _SC_THREAD_PRIO_PROTECT},
12299 #endif
12300 #ifdef _SC_THREAD_PROCESS_SHARED
12301 {"SC_THREAD_PROCESS_SHARED", _SC_THREAD_PROCESS_SHARED},
12302 #endif
12303 #ifdef _SC_THREAD_SAFE_FUNCTIONS
12304 {"SC_THREAD_SAFE_FUNCTIONS", _SC_THREAD_SAFE_FUNCTIONS},
12305 #endif
12306 #ifdef _SC_THREAD_STACK_MIN
12307 {"SC_THREAD_STACK_MIN", _SC_THREAD_STACK_MIN},
12308 #endif
12309 #ifdef _SC_THREAD_THREADS_MAX
12310 {"SC_THREAD_THREADS_MAX", _SC_THREAD_THREADS_MAX},
12311 #endif
12312 #ifdef _SC_TIMERS
12313 {"SC_TIMERS", _SC_TIMERS},
12314 #endif
12315 #ifdef _SC_TIMER_MAX
12316 {"SC_TIMER_MAX", _SC_TIMER_MAX},
12317 #endif
12318 #ifdef _SC_TTY_NAME_MAX
12319 {"SC_TTY_NAME_MAX", _SC_TTY_NAME_MAX},
12320 #endif
12321 #ifdef _SC_TZNAME_MAX
12322 {"SC_TZNAME_MAX", _SC_TZNAME_MAX},
12323 #endif
12324 #ifdef _SC_T_IOV_MAX
12325 {"SC_T_IOV_MAX", _SC_T_IOV_MAX},
12326 #endif
12327 #ifdef _SC_UCHAR_MAX
12328 {"SC_UCHAR_MAX", _SC_UCHAR_MAX},
12329 #endif
12330 #ifdef _SC_UINT_MAX
12331 {"SC_UINT_MAX", _SC_UINT_MAX},
12332 #endif
12333 #ifdef _SC_UIO_MAXIOV
12334 {"SC_UIO_MAXIOV", _SC_UIO_MAXIOV},
12335 #endif
12336 #ifdef _SC_ULONG_MAX
12337 {"SC_ULONG_MAX", _SC_ULONG_MAX},
12338 #endif
12339 #ifdef _SC_USHRT_MAX
12340 {"SC_USHRT_MAX", _SC_USHRT_MAX},
12341 #endif
12342 #ifdef _SC_VERSION
12343 {"SC_VERSION", _SC_VERSION},
12344 #endif
12345 #ifdef _SC_WORD_BIT
12346 {"SC_WORD_BIT", _SC_WORD_BIT},
12347 #endif
12348 #ifdef _SC_XBS5_ILP32_OFF32
12349 {"SC_XBS5_ILP32_OFF32", _SC_XBS5_ILP32_OFF32},
12350 #endif
12351 #ifdef _SC_XBS5_ILP32_OFFBIG
12352 {"SC_XBS5_ILP32_OFFBIG", _SC_XBS5_ILP32_OFFBIG},
12353 #endif
12354 #ifdef _SC_XBS5_LP64_OFF64
12355 {"SC_XBS5_LP64_OFF64", _SC_XBS5_LP64_OFF64},
12356 #endif
12357 #ifdef _SC_XBS5_LPBIG_OFFBIG
12358 {"SC_XBS5_LPBIG_OFFBIG", _SC_XBS5_LPBIG_OFFBIG},
12359 #endif
12360 #ifdef _SC_XOPEN_CRYPT
12361 {"SC_XOPEN_CRYPT", _SC_XOPEN_CRYPT},
12362 #endif
12363 #ifdef _SC_XOPEN_ENH_I18N
12364 {"SC_XOPEN_ENH_I18N", _SC_XOPEN_ENH_I18N},
12365 #endif
12366 #ifdef _SC_XOPEN_LEGACY
12367 {"SC_XOPEN_LEGACY", _SC_XOPEN_LEGACY},
12368 #endif
12369 #ifdef _SC_XOPEN_REALTIME
12370 {"SC_XOPEN_REALTIME", _SC_XOPEN_REALTIME},
12371 #endif
12372 #ifdef _SC_XOPEN_REALTIME_THREADS
12373 {"SC_XOPEN_REALTIME_THREADS", _SC_XOPEN_REALTIME_THREADS},
12374 #endif
12375 #ifdef _SC_XOPEN_SHM
12376 {"SC_XOPEN_SHM", _SC_XOPEN_SHM},
12377 #endif
12378 #ifdef _SC_XOPEN_UNIX
12379 {"SC_XOPEN_UNIX", _SC_XOPEN_UNIX},
12380 #endif
12381 #ifdef _SC_XOPEN_VERSION
12382 {"SC_XOPEN_VERSION", _SC_XOPEN_VERSION},
12383 #endif
12384 #ifdef _SC_XOPEN_XCU_VERSION
12385 {"SC_XOPEN_XCU_VERSION", _SC_XOPEN_XCU_VERSION},
12386 #endif
12387 #ifdef _SC_XOPEN_XPG2
12388 {"SC_XOPEN_XPG2", _SC_XOPEN_XPG2},
12389 #endif
12390 #ifdef _SC_XOPEN_XPG3
12391 {"SC_XOPEN_XPG3", _SC_XOPEN_XPG3},
12392 #endif
12393 #ifdef _SC_XOPEN_XPG4
12394 {"SC_XOPEN_XPG4", _SC_XOPEN_XPG4},
12395 #endif
12396 #ifdef _SC_MINSIGSTKSZ
12397 {"SC_MINSIGSTKSZ", _SC_MINSIGSTKSZ},
12398 #endif
12399 };
12400
12401 static int
12402 3081 conv_sysconf_confname(PyObject *arg, int *valuep)
12403 {
12404 3081 return conv_confname(arg, valuep, posix_constants_sysconf,
12405 sizeof(posix_constants_sysconf)
12406 / sizeof(struct constdef));
12407 }
12408
12409
12410 /*[clinic input]
12411 os.sysconf -> long
12412 name: sysconf_confname
12413 /
12414
12415 Return an integer-valued system configuration variable.
12416 [clinic start generated code]*/
12417
12418 static long
12419 3081 os_sysconf_impl(PyObject *module, int name)
12420 /*[clinic end generated code: output=3662f945fc0cc756 input=279e3430a33f29e4]*/
12421 {
12422 long value;
12423
12424 3081 errno = 0;
12425 3081 value = sysconf(name);
12426
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3081 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
3081 if (value == -1 && errno != 0)
12427 posix_error();
12428 3081 return value;
12429 }
12430 #endif /* HAVE_SYSCONF */
12431
12432
12433 /* This code is used to ensure that the tables of configuration value names
12434 * are in sorted order as required by conv_confname(), and also to build
12435 * the exported dictionaries that are used to publish information about the
12436 * names available on the host platform.
12437 *
12438 * Sorting the table at runtime ensures that the table is properly ordered
12439 * when used, even for platforms we're not able to test on. It also makes
12440 * it easier to add additional entries to the tables.
12441 */
12442
12443 static int
12444 1930068 cmp_constdefs(const void *v1, const void *v2)
12445 {
12446 1930068 const struct constdef *c1 =
12447 (const struct constdef *) v1;
12448 1930068 const struct constdef *c2 =
12449 (const struct constdef *) v2;
12450
12451 1930068 return strcmp(c1->name, c2->name);
12452 }
12453
12454 static int
12455 10212 setup_confname_table(struct constdef *table, size_t tablesize,
12456 const char *tablename, PyObject *module)
12457 {
12458 10212 PyObject *d = NULL;
12459 size_t i;
12460
12461 10212 qsort(table, tablesize, sizeof(struct constdef), cmp_constdefs);
12462 10212 d = PyDict_New();
12463
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10212 times.
10212 if (d == NULL)
12464 return -1;
12465
12466
2/2
✓ Branch 0 taken 616124 times.
✓ Branch 1 taken 10212 times.
626336 for (i=0; i < tablesize; ++i) {
12467 616124 PyObject *o = PyLong_FromLong(table[i].value);
12468
2/4
✓ Branch 0 taken 616124 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 616124 times.
616124 if (o == NULL || PyDict_SetItemString(d, table[i].name, o) == -1) {
12469 Py_XDECREF(o);
12470 Py_DECREF(d);
12471 return -1;
12472 }
12473 616124 Py_DECREF(o);
12474 }
12475 10212 return PyModule_AddObject(module, tablename, d);
12476 }
12477
12478 /* Return -1 on failure, 0 on success. */
12479 static int
12480 3404 setup_confname_tables(PyObject *module)
12481 {
12482 #if defined(HAVE_FPATHCONF) || defined(HAVE_PATHCONF)
12483
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (setup_confname_table(posix_constants_pathconf,
12484 sizeof(posix_constants_pathconf)
12485 / sizeof(struct constdef),
12486 "pathconf_names", module))
12487 return -1;
12488 #endif
12489 #ifdef HAVE_CONFSTR
12490
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (setup_confname_table(posix_constants_confstr,
12491 sizeof(posix_constants_confstr)
12492 / sizeof(struct constdef),
12493 "confstr_names", module))
12494 return -1;
12495 #endif
12496 #ifdef HAVE_SYSCONF
12497
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (setup_confname_table(posix_constants_sysconf,
12498 sizeof(posix_constants_sysconf)
12499 / sizeof(struct constdef),
12500 "sysconf_names", module))
12501 return -1;
12502 #endif
12503 3404 return 0;
12504 }
12505
12506
12507 /*[clinic input]
12508 os.abort
12509
12510 Abort the interpreter immediately.
12511
12512 This function 'dumps core' or otherwise fails in the hardest way possible
12513 on the hosting operating system. This function never returns.
12514 [clinic start generated code]*/
12515
12516 static PyObject *
12517 os_abort_impl(PyObject *module)
12518 /*[clinic end generated code: output=dcf52586dad2467c input=cf2c7d98bc504047]*/
12519 {
12520 abort();
12521 /*NOTREACHED*/
12522 #ifndef __clang__
12523 /* Issue #28152: abort() is declared with __attribute__((__noreturn__)).
12524 GCC emits a warning without "return NULL;" (compiler bug?), but Clang
12525 is smarter and emits a warning on the return. */
12526 Py_FatalError("abort() called from Python code didn't abort!");
12527 return NULL;
12528 #endif
12529 }
12530
12531 #ifdef MS_WINDOWS
12532 /* Grab ShellExecute dynamically from shell32 */
12533 static int has_ShellExecute = -1;
12534 static HINSTANCE (CALLBACK *Py_ShellExecuteW)(HWND, LPCWSTR, LPCWSTR, LPCWSTR,
12535 LPCWSTR, INT);
12536 static int
12537 check_ShellExecute()
12538 {
12539 HINSTANCE hShell32;
12540
12541 /* only recheck */
12542 if (-1 == has_ShellExecute) {
12543 Py_BEGIN_ALLOW_THREADS
12544 /* Security note: this call is not vulnerable to "DLL hijacking".
12545 SHELL32 is part of "KnownDLLs" and so Windows always load
12546 the system SHELL32.DLL, even if there is another SHELL32.DLL
12547 in the DLL search path. */
12548 hShell32 = LoadLibraryW(L"SHELL32");
12549 if (hShell32) {
12550 *(FARPROC*)&Py_ShellExecuteW = GetProcAddress(hShell32,
12551 "ShellExecuteW");
12552 has_ShellExecute = Py_ShellExecuteW != NULL;
12553 } else {
12554 has_ShellExecute = 0;
12555 }
12556 Py_END_ALLOW_THREADS
12557 }
12558 return has_ShellExecute;
12559 }
12560
12561
12562 /*[clinic input]
12563 os.startfile
12564 filepath: path_t
12565 operation: Py_UNICODE = NULL
12566 arguments: Py_UNICODE = NULL
12567 cwd: path_t(nullable=True) = None
12568 show_cmd: int = 1
12569
12570 Start a file with its associated application.
12571
12572 When "operation" is not specified or "open", this acts like
12573 double-clicking the file in Explorer, or giving the file name as an
12574 argument to the DOS "start" command: the file is opened with whatever
12575 application (if any) its extension is associated.
12576 When another "operation" is given, it specifies what should be done with
12577 the file. A typical operation is "print".
12578
12579 "arguments" is passed to the application, but should be omitted if the
12580 file is a document.
12581
12582 "cwd" is the working directory for the operation. If "filepath" is
12583 relative, it will be resolved against this directory. This argument
12584 should usually be an absolute path.
12585
12586 "show_cmd" can be used to override the recommended visibility option.
12587 See the Windows ShellExecute documentation for values.
12588
12589 startfile returns as soon as the associated application is launched.
12590 There is no option to wait for the application to close, and no way
12591 to retrieve the application's exit status.
12592
12593 The filepath is relative to the current directory. If you want to use
12594 an absolute path, make sure the first character is not a slash ("/");
12595 the underlying Win32 ShellExecute function doesn't work if it is.
12596 [clinic start generated code]*/
12597
12598 static PyObject *
12599 os_startfile_impl(PyObject *module, path_t *filepath,
12600 const Py_UNICODE *operation, const Py_UNICODE *arguments,
12601 path_t *cwd, int show_cmd)
12602 /*[clinic end generated code: output=3baa4f9795841880 input=8248997b80669622]*/
12603 {
12604 HINSTANCE rc;
12605
12606 if(!check_ShellExecute()) {
12607 /* If the OS doesn't have ShellExecute, return a
12608 NotImplementedError. */
12609 return PyErr_Format(PyExc_NotImplementedError,
12610 "startfile not available on this platform");
12611 }
12612
12613 if (PySys_Audit("os.startfile", "Ou", filepath->object, operation) < 0) {
12614 return NULL;
12615 }
12616 if (PySys_Audit("os.startfile/2", "OuuOi", filepath->object, operation,
12617 arguments, cwd->object ? cwd->object : Py_None,
12618 show_cmd) < 0) {
12619 return NULL;
12620 }
12621
12622 Py_BEGIN_ALLOW_THREADS
12623 rc = Py_ShellExecuteW((HWND)0, operation, filepath->wide,
12624 arguments, cwd->wide, show_cmd);
12625 Py_END_ALLOW_THREADS
12626
12627 if (rc <= (HINSTANCE)32) {
12628 win32_error_object("startfile", filepath->object);
12629 return NULL;
12630 }
12631 Py_RETURN_NONE;
12632 }
12633 #endif /* MS_WINDOWS */
12634
12635
12636 #ifdef HAVE_GETLOADAVG
12637 /*[clinic input]
12638 os.getloadavg
12639
12640 Return average recent system load information.
12641
12642 Return the number of processes in the system run queue averaged over
12643 the last 1, 5, and 15 minutes as a tuple of three floats.
12644 Raises OSError if the load average was unobtainable.
12645 [clinic start generated code]*/
12646
12647 static PyObject *
12648 os_getloadavg_impl(PyObject *module)
12649 /*[clinic end generated code: output=9ad3a11bfb4f4bd2 input=3d6d826b76d8a34e]*/
12650 {
12651 double loadavg[3];
12652 if (getloadavg(loadavg, 3)!=3) {
12653 PyErr_SetString(PyExc_OSError, "Load averages are unobtainable");
12654 return NULL;
12655 } else
12656 return Py_BuildValue("ddd", loadavg[0], loadavg[1], loadavg[2]);
12657 }
12658 #endif /* HAVE_GETLOADAVG */
12659
12660
12661 /*[clinic input]
12662 os.device_encoding
12663 fd: int
12664
12665 Return a string describing the encoding of a terminal's file descriptor.
12666
12667 The file descriptor must be attached to a terminal.
12668 If the device is not a terminal, return None.
12669 [clinic start generated code]*/
12670
12671 static PyObject *
12672 os_device_encoding_impl(PyObject *module, int fd)
12673 /*[clinic end generated code: output=e0d294bbab7e8c2b input=9e1d4a42b66df312]*/
12674 {
12675 return _Py_device_encoding(fd);
12676 }
12677
12678
12679 #ifdef HAVE_SETRESUID
12680 /*[clinic input]
12681 os.setresuid
12682
12683 ruid: uid_t
12684 euid: uid_t
12685 suid: uid_t
12686 /
12687
12688 Set the current process's real, effective, and saved user ids.
12689 [clinic start generated code]*/
12690
12691 static PyObject *
12692 os_setresuid_impl(PyObject *module, uid_t ruid, uid_t euid, uid_t suid)
12693 /*[clinic end generated code: output=834a641e15373e97 input=9e33cb79a82792f3]*/
12694 {
12695 if (setresuid(ruid, euid, suid) < 0)
12696 return posix_error();
12697 Py_RETURN_NONE;
12698 }
12699 #endif /* HAVE_SETRESUID */
12700
12701
12702 #ifdef HAVE_SETRESGID
12703 /*[clinic input]
12704 os.setresgid
12705
12706 rgid: gid_t
12707 egid: gid_t
12708 sgid: gid_t
12709 /
12710
12711 Set the current process's real, effective, and saved group ids.
12712 [clinic start generated code]*/
12713
12714 static PyObject *
12715 os_setresgid_impl(PyObject *module, gid_t rgid, gid_t egid, gid_t sgid)
12716 /*[clinic end generated code: output=6aa402f3d2e514a9 input=33e9e0785ef426b1]*/
12717 {
12718 if (setresgid(rgid, egid, sgid) < 0)
12719 return posix_error();
12720 Py_RETURN_NONE;
12721 }
12722 #endif /* HAVE_SETRESGID */
12723
12724
12725 #ifdef HAVE_GETRESUID
12726 /*[clinic input]
12727 os.getresuid
12728
12729 Return a tuple of the current process's real, effective, and saved user ids.
12730 [clinic start generated code]*/
12731
12732 static PyObject *
12733 os_getresuid_impl(PyObject *module)
12734 /*[clinic end generated code: output=8e0becff5dece5bf input=41ccfa8e1f6517ad]*/
12735 {
12736 uid_t ruid, euid, suid;
12737 if (getresuid(&ruid, &euid, &suid) < 0)
12738 return posix_error();
12739 return Py_BuildValue("(NNN)", _PyLong_FromUid(ruid),
12740 _PyLong_FromUid(euid),
12741 _PyLong_FromUid(suid));
12742 }
12743 #endif /* HAVE_GETRESUID */
12744
12745
12746 #ifdef HAVE_GETRESGID
12747 /*[clinic input]
12748 os.getresgid
12749
12750 Return a tuple of the current process's real, effective, and saved group ids.
12751 [clinic start generated code]*/
12752
12753 static PyObject *
12754 os_getresgid_impl(PyObject *module)
12755 /*[clinic end generated code: output=2719c4bfcf27fb9f input=517e68db9ca32df6]*/
12756 {
12757 gid_t rgid, egid, sgid;
12758 if (getresgid(&rgid, &egid, &sgid) < 0)
12759 return posix_error();
12760 return Py_BuildValue("(NNN)", _PyLong_FromGid(rgid),
12761 _PyLong_FromGid(egid),
12762 _PyLong_FromGid(sgid));
12763 }
12764 #endif /* HAVE_GETRESGID */
12765
12766
12767 #ifdef USE_XATTRS
12768 /*[clinic input]
12769 os.getxattr
12770
12771 path: path_t(allow_fd=True)
12772 attribute: path_t
12773 *
12774 follow_symlinks: bool = True
12775
12776 Return the value of extended attribute attribute on path.
12777
12778 path may be either a string, a path-like object, or an open file descriptor.
12779 If follow_symlinks is False, and the last element of the path is a symbolic
12780 link, getxattr will examine the symbolic link itself instead of the file
12781 the link points to.
12782
12783 [clinic start generated code]*/
12784
12785 static PyObject *
12786 os_getxattr_impl(PyObject *module, path_t *path, path_t *attribute,
12787 int follow_symlinks)
12788 /*[clinic end generated code: output=5f2f44200a43cff2 input=025789491708f7eb]*/
12789 {
12790 Py_ssize_t i;
12791 PyObject *buffer = NULL;
12792
12793 if (fd_and_follow_symlinks_invalid("getxattr", path->fd, follow_symlinks))
12794 return NULL;
12795
12796 if (PySys_Audit("os.getxattr", "OO", path->object, attribute->object) < 0) {
12797 return NULL;
12798 }
12799
12800 for (i = 0; ; i++) {
12801 void *ptr;
12802 ssize_t result;
12803 static const Py_ssize_t buffer_sizes[] = {128, XATTR_SIZE_MAX, 0};
12804 Py_ssize_t buffer_size = buffer_sizes[i];
12805 if (!buffer_size) {
12806 path_error(path);
12807 return NULL;
12808 }
12809 buffer = PyBytes_FromStringAndSize(NULL, buffer_size);
12810 if (!buffer)
12811 return NULL;
12812 ptr = PyBytes_AS_STRING(buffer);
12813
12814 Py_BEGIN_ALLOW_THREADS;
12815 if (path->fd >= 0)
12816 result = fgetxattr(path->fd, attribute->narrow, ptr, buffer_size);
12817 else if (follow_symlinks)
12818 result = getxattr(path->narrow, attribute->narrow, ptr, buffer_size);
12819 else
12820 result = lgetxattr(path->narrow, attribute->narrow, ptr, buffer_size);
12821 Py_END_ALLOW_THREADS;
12822
12823 if (result < 0) {
12824 Py_DECREF(buffer);
12825 if (errno == ERANGE)
12826 continue;
12827 path_error(path);
12828 return NULL;
12829 }
12830
12831 if (result != buffer_size) {
12832 /* Can only shrink. */
12833 _PyBytes_Resize(&buffer, result);
12834 }
12835 break;
12836 }
12837
12838 return buffer;
12839 }
12840
12841
12842 /*[clinic input]
12843 os.setxattr
12844
12845 path: path_t(allow_fd=True)
12846 attribute: path_t
12847 value: Py_buffer
12848 flags: int = 0
12849 *
12850 follow_symlinks: bool = True
12851
12852 Set extended attribute attribute on path to value.
12853
12854 path may be either a string, a path-like object, or an open file descriptor.
12855 If follow_symlinks is False, and the last element of the path is a symbolic
12856 link, setxattr will modify the symbolic link itself instead of the file
12857 the link points to.
12858
12859 [clinic start generated code]*/
12860
12861 static PyObject *
12862 os_setxattr_impl(PyObject *module, path_t *path, path_t *attribute,
12863 Py_buffer *value, int flags, int follow_symlinks)
12864 /*[clinic end generated code: output=98b83f63fdde26bb input=c17c0103009042f0]*/
12865 {
12866 ssize_t result;
12867
12868 if (fd_and_follow_symlinks_invalid("setxattr", path->fd, follow_symlinks))
12869 return NULL;
12870
12871 if (PySys_Audit("os.setxattr", "OOy#i", path->object, attribute->object,
12872 value->buf, value->len, flags) < 0) {
12873 return NULL;
12874 }
12875
12876 Py_BEGIN_ALLOW_THREADS;
12877 if (path->fd > -1)
12878 result = fsetxattr(path->fd, attribute->narrow,
12879 value->buf, value->len, flags);
12880 else if (follow_symlinks)
12881 result = setxattr(path->narrow, attribute->narrow,
12882 value->buf, value->len, flags);
12883 else
12884 result = lsetxattr(path->narrow, attribute->narrow,
12885 value->buf, value->len, flags);
12886 Py_END_ALLOW_THREADS;
12887
12888 if (result) {
12889 path_error(path);
12890 return NULL;
12891 }
12892
12893 Py_RETURN_NONE;
12894 }
12895
12896
12897 /*[clinic input]
12898 os.removexattr
12899
12900 path: path_t(allow_fd=True)
12901 attribute: path_t
12902 *
12903 follow_symlinks: bool = True
12904
12905 Remove extended attribute attribute on path.
12906
12907 path may be either a string, a path-like object, or an open file descriptor.
12908 If follow_symlinks is False, and the last element of the path is a symbolic
12909 link, removexattr will modify the symbolic link itself instead of the file
12910 the link points to.
12911
12912 [clinic start generated code]*/
12913
12914 static PyObject *
12915 os_removexattr_impl(PyObject *module, path_t *path, path_t *attribute,
12916 int follow_symlinks)
12917 /*[clinic end generated code: output=521a51817980cda6 input=3d9a7d36fe2f7c4e]*/
12918 {
12919 ssize_t result;
12920
12921 if (fd_and_follow_symlinks_invalid("removexattr", path->fd, follow_symlinks))
12922 return NULL;
12923
12924 if (PySys_Audit("os.removexattr", "OO", path->object, attribute->object) < 0) {
12925 return NULL;
12926 }
12927
12928 Py_BEGIN_ALLOW_THREADS;
12929 if (path->fd > -1)
12930 result = fremovexattr(path->fd, attribute->narrow);
12931 else if (follow_symlinks)
12932 result = removexattr(path->narrow, attribute->narrow);
12933 else
12934 result = lremovexattr(path->narrow, attribute->narrow);
12935 Py_END_ALLOW_THREADS;
12936
12937 if (result) {
12938 return path_error(path);
12939 }
12940
12941 Py_RETURN_NONE;
12942 }
12943
12944
12945 /*[clinic input]
12946 os.listxattr
12947
12948 path: path_t(allow_fd=True, nullable=True) = None
12949 *
12950 follow_symlinks: bool = True
12951
12952 Return a list of extended attributes on path.
12953
12954 path may be either None, a string, a path-like object, or an open file descriptor.
12955 if path is None, listxattr will examine the current directory.
12956 If follow_symlinks is False, and the last element of the path is a symbolic
12957 link, listxattr will examine the symbolic link itself instead of the file
12958 the link points to.
12959 [clinic start generated code]*/
12960
12961 static PyObject *
12962 67 os_listxattr_impl(PyObject *module, path_t *path, int follow_symlinks)
12963 /*[clinic end generated code: output=bebdb4e2ad0ce435 input=9826edf9fdb90869]*/
12964 {
12965 Py_ssize_t i;
12966 67 PyObject *result = NULL;
12967 const char *name;
12968 67 char *buffer = NULL;
12969
12970
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 67 times.
67 if (fd_and_follow_symlinks_invalid("listxattr", path->fd, follow_symlinks))
12971 goto exit;
12972
12973
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 67 times.
67 if (PySys_Audit("os.listxattr", "(O)",
12974
1/2
✓ Branch 0 taken 67 times.
✗ Branch 1 not taken.
67 path->object ? path->object : Py_None) < 0) {
12975 return NULL;
12976 }
12977
12978
1/2
✓ Branch 0 taken 67 times.
✗ Branch 1 not taken.
67 name = path->narrow ? path->narrow : ".";
12979
12980 67 for (i = 0; ; i++) {
12981 const char *start, *trace, *end;
12982 ssize_t length;
12983 static const Py_ssize_t buffer_sizes[] = { 256, XATTR_LIST_MAX, 0 };
12984 67 Py_ssize_t buffer_size = buffer_sizes[i];
12985
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 67 times.
67 if (!buffer_size) {
12986 /* ERANGE */
12987 path_error(path);
12988 break;
12989 }
12990 67 buffer = PyMem_Malloc(buffer_size);
12991
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 67 times.
67 if (!buffer) {
12992 PyErr_NoMemory();
12993 break;
12994 }
12995
12996 67 Py_BEGIN_ALLOW_THREADS;
12997
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 67 times.
67 if (path->fd > -1)
12998 length = flistxattr(path->fd, buffer, buffer_size);
12999
1/2
✓ Branch 0 taken 67 times.
✗ Branch 1 not taken.
67 else if (follow_symlinks)
13000 67 length = listxattr(name, buffer, buffer_size);
13001 else
13002 length = llistxattr(name, buffer, buffer_size);
13003 67 Py_END_ALLOW_THREADS;
13004
13005
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 67 times.
67 if (length < 0) {
13006 if (errno == ERANGE) {
13007 PyMem_Free(buffer);
13008 buffer = NULL;
13009 continue;
13010 }
13011 path_error(path);
13012 break;
13013 }
13014
13015 67 result = PyList_New(0);
13016
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 67 times.
67 if (!result) {
13017 goto exit;
13018 }
13019
13020 67 end = buffer + length;
13021
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 67 times.
67 for (trace = start = buffer; trace != end; trace++) {
13022 if (!*trace) {
13023 int error;
13024 PyObject *attribute = PyUnicode_DecodeFSDefaultAndSize(start,
13025 trace - start);
13026 if (!attribute) {
13027 Py_DECREF(result);
13028 result = NULL;
13029 goto exit;
13030 }
13031 error = PyList_Append(result, attribute);
13032 Py_DECREF(attribute);
13033 if (error) {
13034 Py_DECREF(result);
13035 result = NULL;
13036 goto exit;
13037 }
13038 start = trace + 1;
13039 }
13040 }
13041 67 break;
13042 }
13043 67 exit:
13044
1/2
✓ Branch 0 taken 67 times.
✗ Branch 1 not taken.
67 if (buffer)
13045 67 PyMem_Free(buffer);
13046 67 return result;
13047 }
13048 #endif /* USE_XATTRS */
13049
13050
13051 /*[clinic input]
13052 os.urandom
13053
13054 size: Py_ssize_t
13055 /
13056
13057 Return a bytes object containing random bytes suitable for cryptographic use.
13058 [clinic start generated code]*/
13059
13060 static PyObject *
13061 52 os_urandom_impl(PyObject *module, Py_ssize_t size)
13062 /*[clinic end generated code: output=42c5cca9d18068e9 input=4067cdb1b6776c29]*/
13063 {
13064 PyObject *bytes;
13065 int result;
13066
13067
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
52 if (size < 0)
13068 return PyErr_Format(PyExc_ValueError,
13069 "negative argument not allowed");
13070 52 bytes = PyBytes_FromStringAndSize(NULL, size);
13071
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
52 if (bytes == NULL)
13072 return NULL;
13073
13074 52 result = _PyOS_URandom(PyBytes_AS_STRING(bytes), PyBytes_GET_SIZE(bytes));
13075
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
52 if (result == -1) {
13076 Py_DECREF(bytes);
13077 return NULL;
13078 }
13079 52 return bytes;
13080 }
13081
13082 #ifdef HAVE_MEMFD_CREATE
13083 /*[clinic input]
13084 os.memfd_create
13085
13086 name: FSConverter
13087 flags: unsigned_int(bitwise=True, c_default="MFD_CLOEXEC") = MFD_CLOEXEC
13088
13089 [clinic start generated code]*/
13090
13091 static PyObject *
13092 os_memfd_create_impl(PyObject *module, PyObject *name, unsigned int flags)
13093 /*[clinic end generated code: output=6681ede983bdb9a6 input=a42cfc199bcd56e9]*/
13094 {
13095 int fd;
13096 const char *bytes = PyBytes_AS_STRING(name);
13097 Py_BEGIN_ALLOW_THREADS
13098 fd = memfd_create(bytes, flags);
13099 Py_END_ALLOW_THREADS
13100 if (fd == -1) {
13101 return PyErr_SetFromErrno(PyExc_OSError);
13102 }
13103 return PyLong_FromLong(fd);
13104 }
13105 #endif
13106
13107 #ifdef HAVE_EVENTFD
13108 /*[clinic input]
13109 os.eventfd
13110
13111 initval: unsigned_int
13112 flags: int(c_default="EFD_CLOEXEC") = EFD_CLOEXEC
13113
13114 Creates and returns an event notification file descriptor.
13115 [clinic start generated code]*/
13116
13117 static PyObject *
13118 os_eventfd_impl(PyObject *module, unsigned int initval, int flags)
13119 /*[clinic end generated code: output=ce9c9bbd1446f2de input=66203e3c50c4028b]*/
13120
13121 {
13122 /* initval is limited to uint32_t, internal counter is uint64_t */
13123 int fd;
13124 Py_BEGIN_ALLOW_THREADS
13125 fd = eventfd(initval, flags);
13126 Py_END_ALLOW_THREADS
13127 if (fd == -1) {
13128 return PyErr_SetFromErrno(PyExc_OSError);
13129 }
13130 return PyLong_FromLong(fd);
13131 }
13132
13133 /*[clinic input]
13134 os.eventfd_read
13135
13136 fd: fildes
13137
13138 Read eventfd value
13139 [clinic start generated code]*/
13140
13141 static PyObject *
13142 os_eventfd_read_impl(PyObject *module, int fd)
13143 /*[clinic end generated code: output=8f2c7b59a3521fd1 input=110f8b57fa596afe]*/
13144 {
13145 eventfd_t value;
13146 int result;
13147 Py_BEGIN_ALLOW_THREADS
13148 result = eventfd_read(fd, &value);
13149 Py_END_ALLOW_THREADS
13150 if (result == -1) {
13151 return PyErr_SetFromErrno(PyExc_OSError);
13152 }
13153 return PyLong_FromUnsignedLongLong(value);
13154 }
13155
13156 /*[clinic input]
13157 os.eventfd_write
13158
13159 fd: fildes
13160 value: unsigned_long_long
13161
13162 Write eventfd value.
13163 [clinic start generated code]*/
13164
13165 static PyObject *
13166 os_eventfd_write_impl(PyObject *module, int fd, unsigned long long value)
13167 /*[clinic end generated code: output=bebd9040bbf987f5 input=156de8555be5a949]*/
13168 {
13169 int result;
13170 Py_BEGIN_ALLOW_THREADS
13171 result = eventfd_write(fd, value);
13172 Py_END_ALLOW_THREADS
13173 if (result == -1) {
13174 return PyErr_SetFromErrno(PyExc_OSError);
13175 }
13176 Py_RETURN_NONE;
13177 }
13178 #endif /* HAVE_EVENTFD */
13179
13180 /* Terminal size querying */
13181
13182 PyDoc_STRVAR(TerminalSize_docstring,
13183 "A tuple of (columns, lines) for holding terminal window size");
13184
13185 static PyStructSequence_Field TerminalSize_fields[] = {
13186 {"columns", "width of the terminal window in characters"},
13187 {"lines", "height of the terminal window in characters"},
13188 {NULL, NULL}
13189 };
13190
13191 static PyStructSequence_Desc TerminalSize_desc = {
13192 "os.terminal_size",
13193 TerminalSize_docstring,
13194 TerminalSize_fields,
13195 2,
13196 };
13197
13198 #if defined(TERMSIZE_USE_CONIO) || defined(TERMSIZE_USE_IOCTL)
13199 /*[clinic input]
13200 os.get_terminal_size
13201
13202 fd: int(c_default="fileno(stdout)", py_default="<unrepresentable>") = -1
13203 /
13204
13205 Return the size of the terminal window as (columns, lines).
13206
13207 The optional argument fd (default standard output) specifies
13208 which file descriptor should be queried.
13209
13210 If the file descriptor is not connected to a terminal, an OSError
13211 is thrown.
13212
13213 This function will only be defined if an implementation is
13214 available for this system.
13215
13216 shutil.get_terminal_size is the high-level function which should
13217 normally be used, os.get_terminal_size is the low-level implementation.
13218 [clinic start generated code]*/
13219
13220 static PyObject *
13221 51834 os_get_terminal_size_impl(PyObject *module, int fd)
13222 /*[clinic end generated code: output=fbab93acef980508 input=ead5679b82ddb920]*/
13223 {
13224 int columns, lines;
13225 PyObject *termsize;
13226
13227 /* Under some conditions stdout may not be connected and
13228 * fileno(stdout) may point to an invalid file descriptor. For example
13229 * GUI apps don't have valid standard streams by default.
13230 *
13231 * If this happens, and the optional fd argument is not present,
13232 * the ioctl below will fail returning EBADF. This is what we want.
13233 */
13234
13235 #ifdef TERMSIZE_USE_IOCTL
13236 {
13237 struct winsize w;
13238
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 51832 times.
51834 if (ioctl(fd, TIOCGWINSZ, &w))
13239 2 return PyErr_SetFromErrno(PyExc_OSError);
13240 51832 columns = w.ws_col;
13241 51832 lines = w.ws_row;
13242 }
13243 #endif /* TERMSIZE_USE_IOCTL */
13244
13245 #ifdef TERMSIZE_USE_CONIO
13246 {
13247 DWORD nhandle;
13248 HANDLE handle;
13249 CONSOLE_SCREEN_BUFFER_INFO csbi;
13250 switch (fd) {
13251 case 0: nhandle = STD_INPUT_HANDLE;
13252 break;
13253 case 1: nhandle = STD_OUTPUT_HANDLE;
13254 break;
13255 case 2: nhandle = STD_ERROR_HANDLE;
13256 break;
13257 default:
13258 return PyErr_Format(PyExc_ValueError, "bad file descriptor");
13259 }
13260 handle = GetStdHandle(nhandle);
13261 if (handle == NULL)
13262 return PyErr_Format(PyExc_OSError, "handle cannot be retrieved");
13263 if (handle == INVALID_HANDLE_VALUE)
13264 return PyErr_SetFromWindowsErr(0);
13265
13266 if (!GetConsoleScreenBufferInfo(handle, &csbi))
13267 return PyErr_SetFromWindowsErr(0);
13268
13269 columns = csbi.srWindow.Right - csbi.srWindow.Left + 1;
13270 lines = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
13271 }
13272 #endif /* TERMSIZE_USE_CONIO */
13273
13274 51832 PyObject *TerminalSizeType = get_posix_state(module)->TerminalSizeType;
13275 51832 termsize = PyStructSequence_New((PyTypeObject *)TerminalSizeType);
13276
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 51832 times.
51832 if (termsize == NULL)
13277 return NULL;
13278 51832 PyStructSequence_SET_ITEM(termsize, 0, PyLong_FromLong(columns));
13279 51832 PyStructSequence_SET_ITEM(termsize, 1, PyLong_FromLong(lines));
13280
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 51832 times.
51832 if (PyErr_Occurred()) {
13281 Py_DECREF(termsize);
13282 return NULL;
13283 }
13284 51832 return termsize;
13285 }
13286 #endif /* defined(TERMSIZE_USE_CONIO) || defined(TERMSIZE_USE_IOCTL) */
13287
13288
13289 /*[clinic input]
13290 os.cpu_count
13291
13292 Return the number of CPUs in the system; return None if indeterminable.
13293
13294 This number is not equivalent to the number of CPUs the current process can
13295 use. The number of usable CPUs can be obtained with
13296 ``len(os.sched_getaffinity(0))``
13297 [clinic start generated code]*/
13298
13299 static PyObject *
13300 22 os_cpu_count_impl(PyObject *module)
13301 /*[clinic end generated code: output=5fc29463c3936a9c input=e7c8f4ba6dbbadd3]*/
13302 {
13303 22 int ncpu = 0;
13304 #ifdef MS_WINDOWS
13305 ncpu = GetActiveProcessorCount(ALL_PROCESSOR_GROUPS);
13306 #elif defined(__hpux)
13307 ncpu = mpctl(MPC_GETNUMSPUS, NULL, NULL);
13308 #elif defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)
13309 22 ncpu = sysconf(_SC_NPROCESSORS_ONLN);
13310 #elif defined(__VXWORKS__)
13311 ncpu = _Py_popcount32(vxCpuEnabledGet());
13312 #elif defined(__DragonFly__) || \
13313 defined(__OpenBSD__) || \
13314 defined(__FreeBSD__) || \
13315 defined(__NetBSD__) || \
13316 defined(__APPLE__)
13317 int mib[2];
13318 size_t len = sizeof(ncpu);
13319 mib[0] = CTL_HW;
13320 mib[1] = HW_NCPU;
13321 if (sysctl(mib, 2, &ncpu, &len, NULL, 0) != 0)
13322 ncpu = 0;
13323 #endif
13324
1/2
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
22 if (ncpu >= 1)
13325 22 return PyLong_FromLong(ncpu);
13326 else
13327 Py_RETURN_NONE;
13328 }
13329
13330
13331 /*[clinic input]
13332 os.get_inheritable -> bool
13333
13334 fd: int
13335 /
13336
13337 Get the close-on-exe flag of the specified file descriptor.
13338 [clinic start generated code]*/
13339
13340 static int
13341 os_get_inheritable_impl(PyObject *module, int fd)
13342 /*[clinic end generated code: output=0445e20e149aa5b8 input=89ac008dc9ab6b95]*/
13343 {
13344 int return_value;
13345 _Py_BEGIN_SUPPRESS_IPH
13346 return_value = _Py_get_inheritable(fd);
13347 _Py_END_SUPPRESS_IPH
13348 return return_value;
13349 }
13350
13351
13352 /*[clinic input]
13353 os.set_inheritable
13354 fd: int
13355 inheritable: int
13356 /
13357
13358 Set the inheritable flag of the specified file descriptor.
13359 [clinic start generated code]*/
13360
13361 static PyObject *
13362 1512 os_set_inheritable_impl(PyObject *module, int fd, int inheritable)
13363 /*[clinic end generated code: output=f1b1918a2f3c38c2 input=9ceaead87a1e2402]*/
13364 {
13365 int result;
13366
13367 _Py_BEGIN_SUPPRESS_IPH
13368 1512 result = _Py_set_inheritable(fd, inheritable, NULL);
13369 _Py_END_SUPPRESS_IPH
13370
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1512 times.
1512 if (result < 0)
13371 return NULL;
13372 1512 Py_RETURN_NONE;
13373 }
13374
13375
13376 #ifdef MS_WINDOWS
13377 /*[clinic input]
13378 os.get_handle_inheritable -> bool
13379 handle: intptr_t
13380 /
13381
13382 Get the close-on-exe flag of the specified file descriptor.
13383 [clinic start generated code]*/
13384
13385 static int
13386 os_get_handle_inheritable_impl(PyObject *module, intptr_t handle)
13387 /*[clinic end generated code: output=36be5afca6ea84d8 input=cfe99f9c05c70ad1]*/
13388 {
13389 DWORD flags;
13390
13391 if (!GetHandleInformation((HANDLE)handle, &flags)) {
13392 PyErr_SetFromWindowsErr(0);
13393 return -1;
13394 }
13395
13396 return flags & HANDLE_FLAG_INHERIT;
13397 }
13398
13399
13400 /*[clinic input]
13401 os.set_handle_inheritable
13402 handle: intptr_t
13403 inheritable: bool
13404 /
13405
13406 Set the inheritable flag of the specified handle.
13407 [clinic start generated code]*/
13408
13409 static PyObject *
13410 os_set_handle_inheritable_impl(PyObject *module, intptr_t handle,
13411 int inheritable)
13412 /*[clinic end generated code: output=021d74fe6c96baa3 input=7a7641390d8364fc]*/
13413 {
13414 DWORD flags = inheritable ? HANDLE_FLAG_INHERIT : 0;
13415 if (!SetHandleInformation((HANDLE)handle, HANDLE_FLAG_INHERIT, flags)) {
13416 PyErr_SetFromWindowsErr(0);
13417 return NULL;
13418 }
13419 Py_RETURN_NONE;
13420 }
13421 #endif /* MS_WINDOWS */
13422
13423 #ifndef MS_WINDOWS
13424 /*[clinic input]
13425 os.get_blocking -> bool
13426 fd: int
13427 /
13428
13429 Get the blocking mode of the file descriptor.
13430
13431 Return False if the O_NONBLOCK flag is set, True if the flag is cleared.
13432 [clinic start generated code]*/
13433
13434 static int
13435 os_get_blocking_impl(PyObject *module, int fd)
13436 /*[clinic end generated code: output=336a12ad76a61482 input=f4afb59d51560179]*/
13437 {
13438 int blocking;
13439
13440 _Py_BEGIN_SUPPRESS_IPH
13441 blocking = _Py_get_blocking(fd);
13442 _Py_END_SUPPRESS_IPH
13443 return blocking;
13444 }
13445
13446 /*[clinic input]
13447 os.set_blocking
13448 fd: int
13449 blocking: bool(accept={int})
13450 /
13451
13452 Set the blocking mode of the specified file descriptor.
13453
13454 Set the O_NONBLOCK flag if blocking is False,
13455 clear the O_NONBLOCK flag otherwise.
13456 [clinic start generated code]*/
13457
13458 static PyObject *
13459 os_set_blocking_impl(PyObject *module, int fd, int blocking)
13460 /*[clinic end generated code: output=384eb43aa0762a9d input=bf5c8efdc5860ff3]*/
13461 {
13462 int result;
13463
13464 _Py_BEGIN_SUPPRESS_IPH
13465 result = _Py_set_blocking(fd, blocking);
13466 _Py_END_SUPPRESS_IPH
13467 if (result < 0)
13468 return NULL;
13469 Py_RETURN_NONE;
13470 }
13471 #endif /* !MS_WINDOWS */
13472
13473
13474 /*[clinic input]
13475 class os.DirEntry "DirEntry *" "DirEntryType"
13476 [clinic start generated code]*/
13477 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=3c18c7a448247980]*/
13478
13479 typedef struct {
13480 PyObject_HEAD
13481 PyObject *name;
13482 PyObject *path;
13483 PyObject *stat;
13484 PyObject *lstat;
13485 #ifdef MS_WINDOWS
13486 struct _Py_stat_struct win32_lstat;
13487 uint64_t win32_file_index;
13488 int got_file_index;
13489 #else /* POSIX */
13490 #ifdef HAVE_DIRENT_D_TYPE
13491 unsigned char d_type;
13492 #endif
13493 ino_t d_ino;
13494 int dir_fd;
13495 #endif
13496 } DirEntry;
13497
13498 static void
13499 394384 DirEntry_dealloc(DirEntry *entry)
13500 {
13501 394384 PyTypeObject *tp = Py_TYPE(entry);
13502 394384 Py_XDECREF(entry->name);
13503 394384 Py_XDECREF(entry->path);
13504 394384 Py_XDECREF(entry->stat);
13505 394384 Py_XDECREF(entry->lstat);
13506 394384 freefunc free_func = PyType_GetSlot(tp, Py_tp_free);
13507 394384 free_func(entry);
13508 394384 Py_DECREF(tp);
13509 394384 }
13510
13511 /* Forward reference */
13512 static int
13513 DirEntry_test_mode(PyTypeObject *defining_class, DirEntry *self,
13514 int follow_symlinks, unsigned short mode_bits);
13515
13516 /*[clinic input]
13517 os.DirEntry.is_symlink -> bool
13518 defining_class: defining_class
13519 /
13520
13521 Return True if the entry is a symbolic link; cached per entry.
13522 [clinic start generated code]*/
13523
13524 static int
13525 36 os_DirEntry_is_symlink_impl(DirEntry *self, PyTypeObject *defining_class)
13526 /*[clinic end generated code: output=293096d589b6d47c input=e9acc5ee4d511113]*/
13527 {
13528 #ifdef MS_WINDOWS
13529 return (self->win32_lstat.st_mode & S_IFMT) == S_IFLNK;
13530 #elif defined(HAVE_DIRENT_D_TYPE)
13531 /* POSIX */
13532
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 if (self->d_type != DT_UNKNOWN)
13533 36 return self->d_type == DT_LNK;
13534 else
13535 return DirEntry_test_mode(defining_class, self, 0, S_IFLNK);
13536 #else
13537 /* POSIX without d_type */
13538 return DirEntry_test_mode(defining_class, self, 0, S_IFLNK);
13539 #endif
13540 }
13541
13542 static PyObject *
13543 730 DirEntry_fetch_stat(PyObject *module, DirEntry *self, int follow_symlinks)
13544 {
13545 int result;
13546 STRUCT_STAT st;
13547 PyObject *ub;
13548
13549 #ifdef MS_WINDOWS
13550 if (!PyUnicode_FSDecoder(self->path, &ub))
13551 return NULL;
13552 wchar_t *path = PyUnicode_AsWideCharString(ub, NULL);
13553 Py_DECREF(ub);
13554 #else /* POSIX */
13555
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 730 times.
730 if (!PyUnicode_FSConverter(self->path, &ub))
13556 return NULL;
13557 730 const char *path = PyBytes_AS_STRING(ub);
13558
2/2
✓ Branch 0 taken 712 times.
✓ Branch 1 taken 18 times.
730 if (self->dir_fd != DEFAULT_DIR_FD) {
13559 #ifdef HAVE_FSTATAT
13560 if (HAVE_FSTATAT_RUNTIME) {
13561 712 Py_BEGIN_ALLOW_THREADS
13562
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 712 times.
712 result = fstatat(self->dir_fd, path, &st,
13563 follow_symlinks ? 0 : AT_SYMLINK_NOFOLLOW);
13564 712 Py_END_ALLOW_THREADS
13565 } else
13566
13567 #endif /* HAVE_FSTATAT */
13568 {
13569 Py_DECREF(ub);
13570 PyErr_SetString(PyExc_NotImplementedError, "can't fetch stat");
13571 return NULL;
13572 }
13573 }
13574 else
13575 #endif
13576 {
13577 18 Py_BEGIN_ALLOW_THREADS
13578
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (follow_symlinks) {
13579 result = STAT(path, &st);
13580 }
13581 else {
13582 18 result = LSTAT(path, &st);
13583 }
13584 18 Py_END_ALLOW_THREADS
13585 }
13586 #if defined(MS_WINDOWS)
13587 PyMem_Free(path);
13588 #else
13589 730 Py_DECREF(ub);
13590 #endif
13591
13592
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 730 times.
730 if (result != 0)
13593 return path_object_error(self->path);
13594
13595 730 return _pystat_fromstructstat(module, &st);
13596 }
13597
13598 static PyObject *
13599 730 DirEntry_get_lstat(PyTypeObject *defining_class, DirEntry *self)
13600 {
13601
1/2
✓ Branch 0 taken 730 times.
✗ Branch 1 not taken.
730 if (!self->lstat) {
13602 730 PyObject *module = PyType_GetModule(defining_class);
13603 #ifdef MS_WINDOWS
13604 self->lstat = _pystat_fromstructstat(module, &self->win32_lstat);
13605 #else /* POSIX */
13606 730 self->lstat = DirEntry_fetch_stat(module, self, 0);
13607 #endif
13608 }
13609 730 Py_XINCREF(self->lstat);
13610 730 return self->lstat;
13611 }
13612
13613 /*[clinic input]
13614 os.DirEntry.stat
13615 defining_class: defining_class
13616 /
13617 *
13618 follow_symlinks: bool = True
13619
13620 Return stat_result object for the entry; cached per entry.
13621 [clinic start generated code]*/
13622
13623 static PyObject *
13624 766 os_DirEntry_stat_impl(DirEntry *self, PyTypeObject *defining_class,
13625 int follow_symlinks)
13626 /*[clinic end generated code: output=23f803e19c3e780e input=e816273c4e67ee98]*/
13627 {
13628
2/2
✓ Branch 0 taken 712 times.
✓ Branch 1 taken 54 times.
766 if (!follow_symlinks) {
13629 712 return DirEntry_get_lstat(defining_class, self);
13630 }
13631
13632
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 36 times.
54 if (!self->stat) {
13633 18 int result = os_DirEntry_is_symlink_impl(self, defining_class);
13634
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (result == -1) {
13635 return NULL;
13636 }
13637
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (result) {
13638 PyObject *module = PyType_GetModule(defining_class);
13639 self->stat = DirEntry_fetch_stat(module, self, 1);
13640 }
13641 else {
13642 18 self->stat = DirEntry_get_lstat(defining_class, self);
13643 }
13644 }
13645
13646 54 Py_XINCREF(self->stat);
13647 54 return self->stat;
13648 }
13649
13650 /* Set exception and return -1 on error, 0 for False, 1 for True */
13651 static int
13652 54249 DirEntry_test_mode(PyTypeObject *defining_class, DirEntry *self,
13653 int follow_symlinks, unsigned short mode_bits)
13654 {
13655 54249 PyObject *stat = NULL;
13656 54249 PyObject *st_mode = NULL;
13657 long mode;
13658 int result;
13659 #if defined(MS_WINDOWS) || defined(HAVE_DIRENT_D_TYPE)
13660 int is_symlink;
13661 int need_stat;
13662 #endif
13663 #ifdef MS_WINDOWS
13664 unsigned long dir_bits;
13665 #endif
13666
13667 #ifdef MS_WINDOWS
13668 is_symlink = (self->win32_lstat.st_mode & S_IFMT) == S_IFLNK;
13669 need_stat = follow_symlinks && is_symlink;
13670 #elif defined(HAVE_DIRENT_D_TYPE)
13671 54249 is_symlink = self->d_type == DT_LNK;
13672
4/6
✓ Branch 0 taken 54249 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5705 times.
✓ Branch 3 taken 48544 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 5705 times.
54249 need_stat = self->d_type == DT_UNKNOWN || (follow_symlinks && is_symlink);
13673 #endif
13674
13675 #if defined(MS_WINDOWS) || defined(HAVE_DIRENT_D_TYPE)
13676
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54249 times.
54249 if (need_stat) {
13677 #endif
13678 stat = os_DirEntry_stat_impl(self, defining_class, follow_symlinks);
13679 if (!stat) {
13680 if (PyErr_ExceptionMatches(PyExc_FileNotFoundError)) {
13681 /* If file doesn't exist (anymore), then return False
13682 (i.e., say it's not a file/directory) */
13683 PyErr_Clear();
13684 return 0;
13685 }
13686 goto error;
13687 }
13688 _posixstate* state = get_posix_state(PyType_GetModule(defining_class));
13689 st_mode = PyObject_GetAttr(stat, state->st_mode);
13690 if (!st_mode)
13691 goto error;
13692
13693 mode = PyLong_AsLong(st_mode);
13694 if (mode == -1 && PyErr_Occurred())
13695 goto error;
13696 Py_CLEAR(st_mode);
13697 Py_CLEAR(stat);
13698 result = (mode & S_IFMT) == mode_bits;
13699 #if defined(MS_WINDOWS) || defined(HAVE_DIRENT_D_TYPE)
13700 }
13701
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54249 times.
54249 else if (is_symlink) {
13702 assert(mode_bits != S_IFLNK);
13703 result = 0;
13704 }
13705 else {
13706 assert(mode_bits == S_IFDIR || mode_bits == S_IFREG);
13707 #ifdef MS_WINDOWS
13708 dir_bits = self->win32_lstat.st_file_attributes & FILE_ATTRIBUTE_DIRECTORY;
13709 if (mode_bits == S_IFDIR)
13710 result = dir_bits != 0;
13711 else
13712 result = dir_bits == 0;
13713 #else /* POSIX */
13714
1/2
✓ Branch 0 taken 54249 times.
✗ Branch 1 not taken.
54249 if (mode_bits == S_IFDIR)
13715 54249 result = self->d_type == DT_DIR;
13716 else
13717 result = self->d_type == DT_REG;
13718 #endif
13719 }
13720 #endif
13721
13722 54249 return result;
13723
13724 error:
13725 Py_XDECREF(st_mode);
13726 Py_XDECREF(stat);
13727 return -1;
13728 }
13729
13730 /*[clinic input]
13731 os.DirEntry.is_dir -> bool
13732 defining_class: defining_class
13733 /
13734 *
13735 follow_symlinks: bool = True
13736
13737 Return True if the entry is a directory; cached per entry.
13738 [clinic start generated code]*/
13739
13740 static int
13741 54249 os_DirEntry_is_dir_impl(DirEntry *self, PyTypeObject *defining_class,
13742 int follow_symlinks)
13743 /*[clinic end generated code: output=0cd453b9c0987fdf input=1a4ffd6dec9920cb]*/
13744 {
13745 54249 return DirEntry_test_mode(defining_class, self, follow_symlinks, S_IFDIR);
13746 }
13747
13748 /*[clinic input]
13749 os.DirEntry.is_file -> bool
13750 defining_class: defining_class
13751 /
13752 *
13753 follow_symlinks: bool = True
13754
13755 Return True if the entry is a file; cached per entry.
13756 [clinic start generated code]*/
13757
13758 static int
13759 os_DirEntry_is_file_impl(DirEntry *self, PyTypeObject *defining_class,
13760 int follow_symlinks)
13761 /*[clinic end generated code: output=f7c277ab5ba80908 input=0a64c5a12e802e3b]*/
13762 {
13763 return DirEntry_test_mode(defining_class, self, follow_symlinks, S_IFREG);
13764 }
13765
13766 /*[clinic input]
13767 os.DirEntry.inode
13768
13769 Return inode of the entry; cached per entry.
13770 [clinic start generated code]*/
13771
13772 static PyObject *
13773 os_DirEntry_inode_impl(DirEntry *self)
13774 /*[clinic end generated code: output=156bb3a72162440e input=3ee7b872ae8649f0]*/
13775 {
13776 #ifdef MS_WINDOWS
13777 if (!self->got_file_index) {
13778 PyObject *unicode;
13779 STRUCT_STAT stat;
13780 int result;
13781
13782 if (!PyUnicode_FSDecoder(self->path, &unicode))
13783 return NULL;
13784 wchar_t *path = PyUnicode_AsWideCharString(unicode, NULL);
13785 Py_DECREF(unicode);
13786 result = LSTAT(path, &stat);
13787 PyMem_Free(path);
13788
13789 if (result != 0)
13790 return path_object_error(self->path);
13791
13792 self->win32_file_index = stat.st_ino;
13793 self->got_file_index = 1;
13794 }
13795 static_assert(sizeof(unsigned long long) >= sizeof(self->win32_file_index),
13796 "DirEntry.win32_file_index is larger than unsigned long long");
13797 return PyLong_FromUnsignedLongLong(self->win32_file_index);
13798 #else /* POSIX */
13799 static_assert(sizeof(unsigned long long) >= sizeof(self->d_ino),
13800 "DirEntry.d_ino is larger than unsigned long long");
13801 return PyLong_FromUnsignedLongLong(self->d_ino);
13802 #endif
13803 }
13804
13805 static PyObject *
13806 DirEntry_repr(DirEntry *self)
13807 {
13808 return PyUnicode_FromFormat("<DirEntry %R>", self->name);
13809 }
13810
13811 /*[clinic input]
13812 os.DirEntry.__fspath__
13813
13814 Returns the path for the entry.
13815 [clinic start generated code]*/
13816
13817 static PyObject *
13818 36 os_DirEntry___fspath___impl(DirEntry *self)
13819 /*[clinic end generated code: output=6dd7f7ef752e6f4f input=3c49d0cf38df4fac]*/
13820 {
13821 36 Py_INCREF(self->path);
13822 36 return self->path;
13823 }
13824
13825 static PyMemberDef DirEntry_members[] = {
13826 {"name", T_OBJECT_EX, offsetof(DirEntry, name), READONLY,
13827 "the entry's base filename, relative to scandir() \"path\" argument"},
13828 {"path", T_OBJECT_EX, offsetof(DirEntry, path), READONLY,
13829 "the entry's full path name; equivalent to os.path.join(scandir_path, entry.name)"},
13830 {NULL}
13831 };
13832
13833 #include "clinic/posixmodule.c.h"
13834
13835 static PyMethodDef DirEntry_methods[] = {
13836 OS_DIRENTRY_IS_DIR_METHODDEF
13837 OS_DIRENTRY_IS_FILE_METHODDEF
13838 OS_DIRENTRY_IS_SYMLINK_METHODDEF
13839 OS_DIRENTRY_STAT_METHODDEF
13840 OS_DIRENTRY_INODE_METHODDEF
13841 OS_DIRENTRY___FSPATH___METHODDEF
13842 {"__class_getitem__", Py_GenericAlias,
13843 METH_O|METH_CLASS, PyDoc_STR("See PEP 585")},
13844 {NULL}
13845 };
13846
13847 static PyType_Slot DirEntryType_slots[] = {
13848 {Py_tp_dealloc, DirEntry_dealloc},
13849 {Py_tp_repr, DirEntry_repr},
13850 {Py_tp_methods, DirEntry_methods},
13851 {Py_tp_members, DirEntry_members},
13852 {0, 0},
13853 };
13854
13855 static PyType_Spec DirEntryType_spec = {
13856 MODNAME ".DirEntry",
13857 sizeof(DirEntry),
13858 0,
13859 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION,
13860 DirEntryType_slots
13861 };
13862
13863
13864 #ifdef MS_WINDOWS
13865
13866 static wchar_t *
13867 join_path_filenameW(const wchar_t *path_wide, const wchar_t *filename)
13868 {
13869 Py_ssize_t path_len;
13870 Py_ssize_t size;
13871 wchar_t *result;
13872 wchar_t ch;
13873
13874 if (!path_wide) { /* Default arg: "." */
13875 path_wide = L".";
13876 path_len = 1;
13877 }
13878 else {
13879 path_len = wcslen(path_wide);
13880 }
13881
13882 /* The +1's are for the path separator and the NUL */
13883 size = path_len + 1 + wcslen(filename) + 1;
13884 result = PyMem_New(wchar_t, size);
13885 if (!result) {
13886 PyErr_NoMemory();
13887 return NULL;
13888 }
13889 wcscpy(result, path_wide);
13890 if (path_len > 0) {
13891 ch = result[path_len - 1];
13892 if (ch != SEP && ch != ALTSEP && ch != L':')
13893 result[path_len++] = SEP;
13894 wcscpy(result + path_len, filename);
13895 }
13896 return result;
13897 }
13898
13899 static PyObject *
13900 DirEntry_from_find_data(PyObject *module, path_t *path, WIN32_FIND_DATAW *dataW)
13901 {
13902 DirEntry *entry;
13903 BY_HANDLE_FILE_INFORMATION file_info;
13904 ULONG reparse_tag;
13905 wchar_t *joined_path;
13906
13907 PyObject *DirEntryType = get_posix_state(module)->DirEntryType;
13908 entry = PyObject_New(DirEntry, (PyTypeObject *)DirEntryType);
13909 if (!entry)
13910 return NULL;
13911 entry->name = NULL;
13912 entry->path = NULL;
13913 entry->stat = NULL;
13914 entry->lstat = NULL;
13915 entry->got_file_index = 0;
13916
13917 entry->name = PyUnicode_FromWideChar(dataW->cFileName, -1);
13918 if (!entry->name)
13919 goto error;
13920 if (path->narrow) {
13921 Py_SETREF(entry->name, PyUnicode_EncodeFSDefault(entry->name));
13922 if (!entry->name)
13923 goto error;
13924 }
13925
13926 joined_path = join_path_filenameW(path->wide, dataW->cFileName);
13927 if (!joined_path)
13928 goto error;
13929
13930 entry->path = PyUnicode_FromWideChar(joined_path, -1);
13931 PyMem_Free(joined_path);
13932 if (!entry->path)
13933 goto error;
13934 if (path->narrow) {
13935 Py_SETREF(entry->path, PyUnicode_EncodeFSDefault(entry->path));
13936 if (!entry->path)
13937 goto error;
13938 }
13939
13940 find_data_to_file_info(dataW, &file_info, &reparse_tag);
13941 _Py_attribute_data_to_stat(&file_info, reparse_tag, &entry->win32_lstat);
13942
13943 return (PyObject *)entry;
13944
13945 error:
13946 Py_DECREF(entry);
13947 return NULL;
13948 }
13949
13950 #else /* POSIX */
13951
13952 static char *
13953 345840 join_path_filename(const char *path_narrow, const char* filename, Py_ssize_t filename_len)
13954 {
13955 Py_ssize_t path_len;
13956 Py_ssize_t size;
13957 char *result;
13958
13959
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 345840 times.
345840 if (!path_narrow) { /* Default arg: "." */
13960 path_narrow = ".";
13961 path_len = 1;
13962 }
13963 else {
13964 345840 path_len = strlen(path_narrow);
13965 }
13966
13967
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 345840 times.
345840 if (filename_len == -1)
13968 filename_len = strlen(filename);
13969
13970 /* The +1's are for the path separator and the NUL */
13971 345840 size = path_len + 1 + filename_len + 1;
13972
1/2
✓ Branch 0 taken 345840 times.
✗ Branch 1 not taken.
345840 result = PyMem_New(char, size);
13973
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 345840 times.
345840 if (!result) {
13974 PyErr_NoMemory();
13975 return NULL;
13976 }
13977 345840 strcpy(result, path_narrow);
13978
2/4
✓ Branch 0 taken 345840 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 345840 times.
✗ Branch 3 not taken.
345840 if (path_len > 0 && result[path_len - 1] != '/')
13979 345840 result[path_len++] = '/';
13980 345840 strcpy(result + path_len, filename);
13981 345840 return result;
13982 }
13983
13984 static PyObject *
13985 394384 DirEntry_from_posix_info(PyObject *module, path_t *path, const char *name,
13986 Py_ssize_t name_len, ino_t d_ino
13987 #ifdef HAVE_DIRENT_D_TYPE
13988 , unsigned char d_type
13989 #endif
13990 )
13991 {
13992 DirEntry *entry;
13993 char *joined_path;
13994
13995 394384 PyObject *DirEntryType = get_posix_state(module)->DirEntryType;
13996 394384 entry = PyObject_New(DirEntry, (PyTypeObject *)DirEntryType);
13997
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 394384 times.
394384 if (!entry)
13998 return NULL;
13999 394384 entry->name = NULL;
14000 394384 entry->path = NULL;
14001 394384 entry->stat = NULL;
14002 394384 entry->lstat = NULL;
14003
14004
2/2
✓ Branch 0 taken 48544 times.
✓ Branch 1 taken 345840 times.
394384 if (path->fd != -1) {
14005 48544 entry->dir_fd = path->fd;
14006 48544 joined_path = NULL;
14007 }
14008 else {
14009 345840 entry->dir_fd = DEFAULT_DIR_FD;
14010 345840 joined_path = join_path_filename(path->narrow, name, name_len);
14011
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 345840 times.
345840 if (!joined_path)
14012 goto error;
14013 }
14014
14015
3/4
✓ Branch 0 taken 345840 times.
✓ Branch 1 taken 48544 times.
✓ Branch 3 taken 345840 times.
✗ Branch 4 not taken.
394384 if (!path->narrow || !PyObject_CheckBuffer(path->object)) {
14016 394384 entry->name = PyUnicode_DecodeFSDefaultAndSize(name, name_len);
14017
2/2
✓ Branch 0 taken 345840 times.
✓ Branch 1 taken 48544 times.
394384 if (joined_path)
14018 345840 entry->path = PyUnicode_DecodeFSDefault(joined_path);
14019 }
14020 else {
14021 entry->name = PyBytes_FromStringAndSize(name, name_len);
14022 if (joined_path)
14023 entry->path = PyBytes_FromString(joined_path);
14024 }
14025 394384 PyMem_Free(joined_path);
14026
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 394384 times.
394384 if (!entry->name)
14027 goto error;
14028
14029
2/2
✓ Branch 0 taken 48544 times.
✓ Branch 1 taken 345840 times.
394384 if (path->fd != -1) {
14030 48544 entry->path = entry->name;
14031 48544 Py_INCREF(entry->path);
14032 }
14033
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 345840 times.
345840 else if (!entry->path)
14034 goto error;
14035
14036 #ifdef HAVE_DIRENT_D_TYPE
14037 394384 entry->d_type = d_type;
14038 #endif
14039 394384 entry->d_ino = d_ino;
14040
14041 394384 return (PyObject *)entry;
14042
14043 error:
14044 Py_XDECREF(entry);
14045 return NULL;
14046 }
14047
14048 #endif
14049
14050
14051 typedef struct {
14052 PyObject_HEAD
14053 path_t path;
14054 #ifdef MS_WINDOWS
14055 HANDLE handle;
14056 WIN32_FIND_DATAW file_data;
14057 int first_time;
14058 #else /* POSIX */
14059 DIR *dirp;
14060 #endif
14061 #ifdef HAVE_FDOPENDIR
14062 int fd;
14063 #endif
14064 } ScandirIterator;
14065
14066 #ifdef MS_WINDOWS
14067
14068 static int
14069 ScandirIterator_is_closed(ScandirIterator *iterator)
14070 {
14071 return iterator->handle == INVALID_HANDLE_VALUE;
14072 }
14073
14074 static void
14075 ScandirIterator_closedir(ScandirIterator *iterator)
14076 {
14077 HANDLE handle = iterator->handle;
14078
14079 if (handle == INVALID_HANDLE_VALUE)
14080 return;
14081
14082 iterator->handle = INVALID_HANDLE_VALUE;
14083 Py_BEGIN_ALLOW_THREADS
14084 FindClose(handle);
14085 Py_END_ALLOW_THREADS
14086 }
14087
14088 static PyObject *
14089 ScandirIterator_iternext(ScandirIterator *iterator)
14090 {
14091 WIN32_FIND_DATAW *file_data = &iterator->file_data;
14092 BOOL success;
14093 PyObject *entry;
14094
14095 /* Happens if the iterator is iterated twice, or closed explicitly */
14096 if (iterator->handle == INVALID_HANDLE_VALUE)
14097 return NULL;
14098
14099 while (1) {
14100 if (!iterator->first_time) {
14101 Py_BEGIN_ALLOW_THREADS
14102 success = FindNextFileW(iterator->handle, file_data);
14103 Py_END_ALLOW_THREADS
14104 if (!success) {
14105 /* Error or no more files */
14106 if (GetLastError() != ERROR_NO_MORE_FILES)
14107 path_error(&iterator->path);
14108 break;
14109 }
14110 }
14111 iterator->first_time = 0;
14112
14113 /* Skip over . and .. */
14114 if (wcscmp(file_data->cFileName, L".") != 0 &&
14115 wcscmp(file_data->cFileName, L"..") != 0)
14116 {
14117 PyObject *module = PyType_GetModule(Py_TYPE(iterator));
14118 entry = DirEntry_from_find_data(module, &iterator->path, file_data);
14119 if (!entry)
14120 break;
14121 return entry;
14122 }
14123
14124 /* Loop till we get a non-dot directory or finish iterating */
14125 }
14126
14127 /* Error or no more files */
14128 ScandirIterator_closedir(iterator);
14129 return NULL;
14130 }
14131
14132 #else /* POSIX */
14133
14134 static int
14135 2472 ScandirIterator_is_closed(ScandirIterator *iterator)
14136 {
14137 2472 return !iterator->dirp;
14138 }
14139
14140 static void
14141 4898 ScandirIterator_closedir(ScandirIterator *iterator)
14142 {
14143 4898 DIR *dirp = iterator->dirp;
14144
14145
2/2
✓ Branch 0 taken 2449 times.
✓ Branch 1 taken 2449 times.
4898 if (!dirp)
14146 2449 return;
14147
14148 2449 iterator->dirp = NULL;
14149 2449 Py_BEGIN_ALLOW_THREADS
14150 #ifdef HAVE_FDOPENDIR
14151
2/2
✓ Branch 0 taken 1268 times.
✓ Branch 1 taken 1181 times.
2449 if (iterator->path.fd != -1)
14152 1268 rewinddir(dirp);
14153 #endif
14154 2449 closedir(dirp);
14155 2449 Py_END_ALLOW_THREADS
14156 2449 return;
14157 }
14158
14159 static PyObject *
14160 396833 ScandirIterator_iternext(ScandirIterator *iterator)
14161 {
14162 struct dirent *direntp;
14163 Py_ssize_t name_len;
14164 int is_dot;
14165 PyObject *entry;
14166
14167 /* Happens if the iterator is iterated twice, or closed explicitly */
14168
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 396833 times.
396833 if (!iterator->dirp)
14169 return NULL;
14170
14171 while (1) {
14172 401731 errno = 0;
14173 401731 Py_BEGIN_ALLOW_THREADS
14174 401731 direntp = readdir(iterator->dirp);
14175 401731 Py_END_ALLOW_THREADS
14176
14177
2/2
✓ Branch 0 taken 2449 times.
✓ Branch 1 taken 399282 times.
401731 if (!direntp) {
14178 /* Error or no more files */
14179
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2449 times.
2449 if (errno != 0)
14180 path_error(&iterator->path);
14181 2449 break;
14182 }
14183
14184 /* Skip over . and .. */
14185 399282 name_len = NAMLEN(direntp);
14186
4/4
✓ Branch 0 taken 5166 times.
✓ Branch 1 taken 394116 times.
✓ Branch 2 taken 2717 times.
✓ Branch 3 taken 2449 times.
401999 is_dot = direntp->d_name[0] == '.' &&
14187
3/4
✓ Branch 0 taken 2449 times.
✓ Branch 1 taken 268 times.
✓ Branch 2 taken 2449 times.
✗ Branch 3 not taken.
2717 (name_len == 1 || (direntp->d_name[1] == '.' && name_len == 2));
14188
2/2
✓ Branch 0 taken 394384 times.
✓ Branch 1 taken 4898 times.
399282 if (!is_dot) {
14189 394384 PyObject *module = PyType_GetModule(Py_TYPE(iterator));
14190 394384 entry = DirEntry_from_posix_info(module,
14191 394384 &iterator->path, direntp->d_name,
14192 name_len, direntp->d_ino
14193 #ifdef HAVE_DIRENT_D_TYPE
14194 394384 , direntp->d_type
14195 #endif
14196 );
14197
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 394384 times.
394384 if (!entry)
14198 break;
14199 394384 return entry;
14200 }
14201
14202 /* Loop till we get a non-dot directory or finish iterating */
14203 }
14204
14205 /* Error or no more files */
14206 2449 ScandirIterator_closedir(iterator);
14207 2449 return NULL;
14208 }
14209
14210 #endif
14211
14212 static PyObject *
14213 ScandirIterator_close(ScandirIterator *self, PyObject *args)
14214 {
14215 ScandirIterator_closedir(self);
14216 Py_RETURN_NONE;
14217 }
14218
14219 static PyObject *
14220 2449 ScandirIterator_enter(PyObject *self, PyObject *args)
14221 {
14222 2449 Py_INCREF(self);
14223 2449 return self;
14224 }
14225
14226 static PyObject *
14227 2449 ScandirIterator_exit(ScandirIterator *self, PyObject *args)
14228 {
14229 2449 ScandirIterator_closedir(self);
14230 2449 Py_RETURN_NONE;
14231 }
14232
14233 static void
14234 2472 ScandirIterator_finalize(ScandirIterator *iterator)
14235 {
14236 PyObject *error_type, *error_value, *error_traceback;
14237
14238 /* Save the current exception, if any. */
14239 2472 PyErr_Fetch(&error_type, &error_value, &error_traceback);
14240
14241
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2472 times.
2472 if (!ScandirIterator_is_closed(iterator)) {
14242 ScandirIterator_closedir(iterator);
14243
14244 if (PyErr_ResourceWarning((PyObject *)iterator, 1,
14245 "unclosed scandir iterator %R", iterator)) {
14246 /* Spurious errors can appear at shutdown */
14247 if (PyErr_ExceptionMatches(PyExc_Warning)) {
14248 PyErr_WriteUnraisable((PyObject *) iterator);
14249 }
14250 }
14251 }
14252
14253 2472 path_cleanup(&iterator->path);
14254
14255 /* Restore the saved exception. */
14256 2472 PyErr_Restore(error_type, error_value, error_traceback);
14257 2472 }
14258
14259 static void
14260 2472 ScandirIterator_dealloc(ScandirIterator *iterator)
14261 {
14262 2472 PyTypeObject *tp = Py_TYPE(iterator);
14263
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2472 times.
2472 if (PyObject_CallFinalizerFromDealloc((PyObject *)iterator) < 0)
14264 return;
14265
14266 2472 freefunc free_func = PyType_GetSlot(tp, Py_tp_free);
14267 2472 free_func(iterator);
14268 2472 Py_DECREF(tp);
14269 }
14270
14271 static PyMethodDef ScandirIterator_methods[] = {
14272 {"__enter__", (PyCFunction)ScandirIterator_enter, METH_NOARGS},
14273 {"__exit__", (PyCFunction)ScandirIterator_exit, METH_VARARGS},
14274 {"close", (PyCFunction)ScandirIterator_close, METH_NOARGS},
14275 {NULL}
14276 };
14277
14278 static PyType_Slot ScandirIteratorType_slots[] = {
14279 {Py_tp_dealloc, ScandirIterator_dealloc},
14280 {Py_tp_finalize, ScandirIterator_finalize},
14281 {Py_tp_iter, PyObject_SelfIter},
14282 {Py_tp_iternext, ScandirIterator_iternext},
14283 {Py_tp_methods, ScandirIterator_methods},
14284 {0, 0},
14285 };
14286
14287 static PyType_Spec ScandirIteratorType_spec = {
14288 MODNAME ".ScandirIterator",
14289 sizeof(ScandirIterator),
14290 0,
14291 // bpo-40549: Py_TPFLAGS_BASETYPE should not be used, since
14292 // PyType_GetModule(Py_TYPE(self)) doesn't work on a subclass instance.
14293 (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_FINALIZE
14294 | Py_TPFLAGS_DISALLOW_INSTANTIATION),
14295 ScandirIteratorType_slots
14296 };
14297
14298 /*[clinic input]
14299 os.scandir
14300
14301 path : path_t(nullable=True, allow_fd='PATH_HAVE_FDOPENDIR') = None
14302
14303 Return an iterator of DirEntry objects for given path.
14304
14305 path can be specified as either str, bytes, or a path-like object. If path
14306 is bytes, the names of yielded DirEntry objects will also be bytes; in
14307 all other circumstances they will be str.
14308
14309 If path is None, uses the path='.'.
14310 [clinic start generated code]*/
14311
14312 static PyObject *
14313 2472 os_scandir_impl(PyObject *module, path_t *path)
14314 /*[clinic end generated code: output=6eb2668b675ca89e input=6bdd312708fc3bb0]*/
14315 {
14316 ScandirIterator *iterator;
14317 #ifdef MS_WINDOWS
14318 wchar_t *path_strW;
14319 #else
14320 const char *path_str;
14321 #ifdef HAVE_FDOPENDIR
14322 2472 int fd = -1;
14323 #endif
14324 #endif
14325
14326
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2472 times.
2472 if (PySys_Audit("os.scandir", "O",
14327
1/2
✓ Branch 0 taken 2472 times.
✗ Branch 1 not taken.
2472 path->object ? path->object : Py_None) < 0) {
14328 return NULL;
14329 }
14330
14331 2472 PyObject *ScandirIteratorType = get_posix_state(module)->ScandirIteratorType;
14332 2472 iterator = PyObject_New(ScandirIterator, (PyTypeObject *)ScandirIteratorType);
14333
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2472 times.
2472 if (!iterator)
14334 return NULL;
14335
14336 #ifdef MS_WINDOWS
14337 iterator->handle = INVALID_HANDLE_VALUE;
14338 #else
14339 2472 iterator->dirp = NULL;
14340 #endif
14341
14342 /* Move the ownership to iterator->path */
14343 2472 memcpy(&iterator->path, path, sizeof(path_t));
14344 2472 memset(path, 0, sizeof(path_t));
14345
14346 #ifdef MS_WINDOWS
14347 iterator->first_time = 1;
14348
14349 path_strW = join_path_filenameW(iterator->path.wide, L"*.*");
14350 if (!path_strW)
14351 goto error;
14352
14353 Py_BEGIN_ALLOW_THREADS
14354 iterator->handle = FindFirstFileW(path_strW, &iterator->file_data);
14355 Py_END_ALLOW_THREADS
14356
14357 PyMem_Free(path_strW);
14358
14359 if (iterator->handle == INVALID_HANDLE_VALUE) {
14360 path_error(&iterator->path);
14361 goto error;
14362 }
14363 #else /* POSIX */
14364 2472 errno = 0;
14365 #ifdef HAVE_FDOPENDIR
14366
2/2
✓ Branch 0 taken 1268 times.
✓ Branch 1 taken 1204 times.
2472 if (iterator->path.fd != -1) {
14367 if (HAVE_FDOPENDIR_RUNTIME) {
14368 /* closedir() closes the FD, so we duplicate it */
14369 1268 fd = _Py_dup(iterator->path.fd);
14370
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1268 times.
1268 if (fd == -1)
14371 goto error;
14372
14373 1268 Py_BEGIN_ALLOW_THREADS
14374 1268 iterator->dirp = fdopendir(fd);
14375 1268 Py_END_ALLOW_THREADS
14376 } else {
14377 PyErr_SetString(PyExc_TypeError,
14378 "scandir: path should be string, bytes, os.PathLike or None, not int");
14379 return NULL;
14380 }
14381 }
14382 else
14383 #endif
14384 {
14385
1/2
✓ Branch 0 taken 1204 times.
✗ Branch 1 not taken.
1204 if (iterator->path.narrow)
14386 1204 path_str = iterator->path.narrow;
14387 else
14388 path_str = ".";
14389
14390 1204 Py_BEGIN_ALLOW_THREADS
14391 1204 iterator->dirp = opendir(path_str);
14392 1204 Py_END_ALLOW_THREADS
14393 }
14394
14395
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 2449 times.
2472 if (!iterator->dirp) {
14396 23 path_error(&iterator->path);
14397 #ifdef HAVE_FDOPENDIR
14398
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
23 if (fd != -1) {
14399 Py_BEGIN_ALLOW_THREADS
14400 close(fd);
14401 Py_END_ALLOW_THREADS
14402 }
14403 #endif
14404 23 goto error;
14405 }
14406 #endif
14407
14408 2449 return (PyObject *)iterator;
14409
14410 23 error:
14411 23 Py_DECREF(iterator);
14412 23 return NULL;
14413 }
14414
14415 /*
14416 Return the file system path representation of the object.
14417
14418 If the object is str or bytes, then allow it to pass through with
14419 an incremented refcount. If the object defines __fspath__(), then
14420 return the result of that method. All other types raise a TypeError.
14421 */
14422 PyObject *
14423 9093976 PyOS_FSPath(PyObject *path)
14424 {
14425 /* For error message reasons, this function is manually inlined in
14426 path_converter(). */
14427 9093976 PyObject *func = NULL;
14428 9093976 PyObject *path_repr = NULL;
14429
14430
4/4
✓ Branch 2 taken 312986 times.
✓ Branch 3 taken 8780990 times.
✓ Branch 6 taken 308693 times.
✓ Branch 7 taken 4293 times.
9093976 if (PyUnicode_Check(path) || PyBytes_Check(path)) {
14431 9089683 Py_INCREF(path);
14432 9089683 return path;
14433 }
14434
14435 4293 func = _PyObject_LookupSpecial(path, &_Py_ID(__fspath__));
14436
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4293 times.
4293 if (NULL == func) {
14437 return PyErr_Format(PyExc_TypeError,
14438 "expected str, bytes or os.PathLike object, "
14439 "not %.200s",
14440 _PyType_Name(Py_TYPE(path)));
14441 }
14442
14443 4293 path_repr = _PyObject_CallNoArgs(func);
14444 4293 Py_DECREF(func);
14445
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4293 times.
4293 if (NULL == path_repr) {
14446 return NULL;
14447 }
14448
14449
1/4
✗ Branch 2 not taken.
✓ Branch 3 taken 4293 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
4293 if (!(PyUnicode_Check(path_repr) || PyBytes_Check(path_repr))) {
14450 PyErr_Format(PyExc_TypeError,
14451 "expected %.200s.__fspath__() to return str or bytes, "
14452 "not %.200s", _PyType_Name(Py_TYPE(path)),
14453 _PyType_Name(Py_TYPE(path_repr)));
14454 Py_DECREF(path_repr);
14455 return NULL;
14456 }
14457
14458 4293 return path_repr;
14459 }
14460
14461 /*[clinic input]
14462 os.fspath
14463
14464 path: object
14465
14466 Return the file system path representation of the object.
14467
14468 If the object is str or bytes, then allow it to pass through as-is. If the
14469 object defines __fspath__(), then return the result of that method. All other
14470 types raise a TypeError.
14471 [clinic start generated code]*/
14472
14473 static PyObject *
14474 4998603 os_fspath_impl(PyObject *module, PyObject *path)
14475 /*[clinic end generated code: output=c3c3b78ecff2914f input=e357165f7b22490f]*/
14476 {
14477 4998603 return PyOS_FSPath(path);
14478 }
14479
14480 #ifdef HAVE_GETRANDOM_SYSCALL
14481 /*[clinic input]
14482 os.getrandom
14483
14484 size: Py_ssize_t
14485 flags: int=0
14486
14487 Obtain a series of random bytes.
14488 [clinic start generated code]*/
14489
14490 static PyObject *
14491 os_getrandom_impl(PyObject *module, Py_ssize_t size, int flags)
14492 /*[clinic end generated code: output=b3a618196a61409c input=59bafac39c594947]*/
14493 {
14494 PyObject *bytes;
14495 Py_ssize_t n;
14496
14497 if (size < 0) {
14498 errno = EINVAL;
14499 return posix_error();
14500 }
14501
14502 bytes = PyBytes_FromStringAndSize(NULL, size);
14503 if (bytes == NULL) {
14504 PyErr_NoMemory();
14505 return NULL;
14506 }
14507
14508 while (1) {
14509 n = syscall(SYS_getrandom,
14510 PyBytes_AS_STRING(bytes),
14511 PyBytes_GET_SIZE(bytes),
14512 flags);
14513 if (n < 0 && errno == EINTR) {
14514 if (PyErr_CheckSignals() < 0) {
14515 goto error;
14516 }
14517
14518 /* getrandom() was interrupted by a signal: retry */
14519 continue;
14520 }
14521 break;
14522 }
14523
14524 if (n < 0) {
14525 PyErr_SetFromErrno(PyExc_OSError);
14526 goto error;
14527 }
14528
14529 if (n != size) {
14530 _PyBytes_Resize(&bytes, n);
14531 }
14532
14533 return bytes;
14534
14535 error:
14536 Py_DECREF(bytes);
14537 return NULL;
14538 }
14539 #endif /* HAVE_GETRANDOM_SYSCALL */
14540
14541 #ifdef MS_WINDOWS
14542 /* bpo-36085: Helper functions for managing DLL search directories
14543 * on win32
14544 */
14545
14546 typedef DLL_DIRECTORY_COOKIE (WINAPI *PAddDllDirectory)(PCWSTR newDirectory);
14547 typedef BOOL (WINAPI *PRemoveDllDirectory)(DLL_DIRECTORY_COOKIE cookie);
14548
14549 /*[clinic input]
14550 os._add_dll_directory
14551
14552 path: path_t
14553
14554 Add a path to the DLL search path.
14555
14556 This search path is used when resolving dependencies for imported
14557 extension modules (the module itself is resolved through sys.path),
14558 and also by ctypes.
14559
14560 Returns an opaque value that may be passed to os.remove_dll_directory
14561 to remove this directory from the search path.
14562 [clinic start generated code]*/
14563
14564 static PyObject *
14565 os__add_dll_directory_impl(PyObject *module, path_t *path)
14566 /*[clinic end generated code: output=80b025daebb5d683 input=1de3e6c13a5808c8]*/
14567 {
14568 HMODULE hKernel32;
14569 PAddDllDirectory AddDllDirectory;
14570 DLL_DIRECTORY_COOKIE cookie = 0;
14571 DWORD err = 0;
14572
14573 if (PySys_Audit("os.add_dll_directory", "(O)", path->object) < 0) {
14574 return NULL;
14575 }
14576
14577 /* For Windows 7, we have to load this. As this will be a fairly
14578 infrequent operation, just do it each time. Kernel32 is always
14579 loaded. */
14580 Py_BEGIN_ALLOW_THREADS
14581 if (!(hKernel32 = GetModuleHandleW(L"kernel32")) ||
14582 !(AddDllDirectory = (PAddDllDirectory)GetProcAddress(
14583 hKernel32, "AddDllDirectory")) ||
14584 !(cookie = (*AddDllDirectory)(path->wide))) {
14585 err = GetLastError();
14586 }
14587 Py_END_ALLOW_THREADS
14588
14589 if (err) {
14590 return win32_error_object_err("add_dll_directory",
14591 path->object, err);
14592 }
14593
14594 return PyCapsule_New(cookie, "DLL directory cookie", NULL);
14595 }
14596
14597 /*[clinic input]
14598 os._remove_dll_directory
14599
14600 cookie: object
14601
14602 Removes a path from the DLL search path.
14603
14604 The parameter is an opaque value that was returned from
14605 os.add_dll_directory. You can only remove directories that you added
14606 yourself.
14607 [clinic start generated code]*/
14608
14609 static PyObject *
14610 os__remove_dll_directory_impl(PyObject *module, PyObject *cookie)
14611 /*[clinic end generated code: output=594350433ae535bc input=c1d16a7e7d9dc5dc]*/
14612 {
14613 HMODULE hKernel32;
14614 PRemoveDllDirectory RemoveDllDirectory;
14615 DLL_DIRECTORY_COOKIE cookieValue;
14616 DWORD err = 0;
14617
14618 if (!PyCapsule_IsValid(cookie, "DLL directory cookie")) {
14619 PyErr_SetString(PyExc_TypeError,
14620 "Provided cookie was not returned from os.add_dll_directory");
14621 return NULL;
14622 }
14623
14624 cookieValue = (DLL_DIRECTORY_COOKIE)PyCapsule_GetPointer(
14625 cookie, "DLL directory cookie");
14626
14627 /* For Windows 7, we have to load this. As this will be a fairly
14628 infrequent operation, just do it each time. Kernel32 is always
14629 loaded. */
14630 Py_BEGIN_ALLOW_THREADS
14631 if (!(hKernel32 = GetModuleHandleW(L"kernel32")) ||
14632 !(RemoveDllDirectory = (PRemoveDllDirectory)GetProcAddress(
14633 hKernel32, "RemoveDllDirectory")) ||
14634 !(*RemoveDllDirectory)(cookieValue)) {
14635 err = GetLastError();
14636 }
14637 Py_END_ALLOW_THREADS
14638
14639 if (err) {
14640 return win32_error_object_err("remove_dll_directory",
14641 NULL, err);
14642 }
14643
14644 if (PyCapsule_SetName(cookie, NULL)) {
14645 return NULL;
14646 }
14647
14648 Py_RETURN_NONE;
14649 }
14650
14651 #endif
14652
14653
14654 /* Only check if WIFEXITED is available: expect that it comes
14655 with WEXITSTATUS, WIFSIGNALED, etc.
14656
14657 os.waitstatus_to_exitcode() is implemented in C and not in Python, so
14658 subprocess can safely call it during late Python finalization without
14659 risking that used os attributes were set to None by finalize_modules(). */
14660 #if defined(WIFEXITED) || defined(MS_WINDOWS)
14661 /*[clinic input]
14662 os.waitstatus_to_exitcode
14663
14664 status as status_obj: object
14665
14666 Convert a wait status to an exit code.
14667
14668 On Unix:
14669
14670 * If WIFEXITED(status) is true, return WEXITSTATUS(status).
14671 * If WIFSIGNALED(status) is true, return -WTERMSIG(status).
14672 * Otherwise, raise a ValueError.
14673
14674 On Windows, return status shifted right by 8 bits.
14675
14676 On Unix, if the process is being traced or if waitpid() was called with
14677 WUNTRACED option, the caller must first check if WIFSTOPPED(status) is true.
14678 This function must not be called if WIFSTOPPED(status) is true.
14679 [clinic start generated code]*/
14680
14681 static PyObject *
14682 6714 os_waitstatus_to_exitcode_impl(PyObject *module, PyObject *status_obj)
14683 /*[clinic end generated code: output=db50b1b0ba3c7153 input=7fe2d7fdaea3db42]*/
14684 {
14685 #ifndef MS_WINDOWS
14686 6714 int status = _PyLong_AsInt(status_obj);
14687
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 6714 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
6714 if (status == -1 && PyErr_Occurred()) {
14688 return NULL;
14689 }
14690
14691 WAIT_TYPE wait_status;
14692 6714 WAIT_STATUS_INT(wait_status) = status;
14693 int exitcode;
14694
1/2
✓ Branch 0 taken 6714 times.
✗ Branch 1 not taken.
6714 if (WIFEXITED(wait_status)) {
14695 6714 exitcode = WEXITSTATUS(wait_status);
14696 /* Sanity check to provide warranty on the function behavior.
14697 It should not occur in practice */
14698
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6714 times.
6714 if (exitcode < 0) {
14699 PyErr_Format(PyExc_ValueError, "invalid WEXITSTATUS: %i", exitcode);
14700 return NULL;
14701 }
14702 }
14703 else if (WIFSIGNALED(wait_status)) {
14704 int signum = WTERMSIG(wait_status);
14705 /* Sanity check to provide warranty on the function behavior.
14706 It should not occurs in practice */
14707 if (signum <= 0) {
14708 PyErr_Format(PyExc_ValueError, "invalid WTERMSIG: %i", signum);
14709 return NULL;
14710 }
14711 exitcode = -signum;
14712 } else if (WIFSTOPPED(wait_status)) {
14713 /* Status only received if the process is being traced
14714 or if waitpid() was called with WUNTRACED option. */
14715 int signum = WSTOPSIG(wait_status);
14716 PyErr_Format(PyExc_ValueError,
14717 "process stopped by delivery of signal %i",
14718 signum);
14719 return NULL;
14720 }
14721 else {
14722 PyErr_Format(PyExc_ValueError, "invalid wait status: %i", status);
14723 return NULL;
14724 }
14725 6714 return PyLong_FromLong(exitcode);
14726 #else
14727 /* Windows implementation: see os.waitpid() implementation
14728 which uses _cwait(). */
14729 unsigned long long status = PyLong_AsUnsignedLongLong(status_obj);
14730 if (status == (unsigned long long)-1 && PyErr_Occurred()) {
14731 return NULL;
14732 }
14733
14734 unsigned long long exitcode = (status >> 8);
14735 /* ExitProcess() accepts an UINT type:
14736 reject exit code which doesn't fit in an UINT */
14737 if (exitcode > UINT_MAX) {
14738 PyErr_Format(PyExc_ValueError, "invalid exit code: %llu", exitcode);
14739 return NULL;
14740 }
14741 return PyLong_FromUnsignedLong((unsigned long)exitcode);
14742 #endif
14743 }
14744 #endif
14745
14746
14747 static PyMethodDef posix_methods[] = {
14748
14749 OS_STAT_METHODDEF
14750 OS_ACCESS_METHODDEF
14751 OS_TTYNAME_METHODDEF
14752 OS_CHDIR_METHODDEF
14753 OS_CHFLAGS_METHODDEF
14754 OS_CHMOD_METHODDEF
14755 OS_FCHMOD_METHODDEF
14756 OS_LCHMOD_METHODDEF
14757 OS_CHOWN_METHODDEF
14758 OS_FCHOWN_METHODDEF
14759 OS_LCHOWN_METHODDEF
14760 OS_LCHFLAGS_METHODDEF
14761 OS_CHROOT_METHODDEF
14762 OS_CTERMID_METHODDEF
14763 OS_GETCWD_METHODDEF
14764 OS_GETCWDB_METHODDEF
14765 OS_LINK_METHODDEF
14766 OS_LISTDIR_METHODDEF
14767 OS_LSTAT_METHODDEF
14768 OS_MKDIR_METHODDEF
14769 OS_NICE_METHODDEF
14770 OS_GETPRIORITY_METHODDEF
14771 OS_SETPRIORITY_METHODDEF
14772 OS_POSIX_SPAWN_METHODDEF
14773 OS_POSIX_SPAWNP_METHODDEF
14774 OS_READLINK_METHODDEF
14775 OS_COPY_FILE_RANGE_METHODDEF
14776 OS_SPLICE_METHODDEF
14777 OS_RENAME_METHODDEF
14778 OS_REPLACE_METHODDEF
14779 OS_RMDIR_METHODDEF
14780 OS_SYMLINK_METHODDEF
14781 OS_SYSTEM_METHODDEF
14782 OS_UMASK_METHODDEF
14783 OS_UNAME_METHODDEF
14784 OS_UNLINK_METHODDEF
14785 OS_REMOVE_METHODDEF
14786 OS_UTIME_METHODDEF
14787 OS_TIMES_METHODDEF
14788 OS__EXIT_METHODDEF
14789 OS__FCOPYFILE_METHODDEF
14790 OS_EXECV_METHODDEF
14791 OS_EXECVE_METHODDEF
14792 OS_SPAWNV_METHODDEF
14793 OS_SPAWNVE_METHODDEF
14794 OS_FORK1_METHODDEF
14795 OS_FORK_METHODDEF
14796 OS_REGISTER_AT_FORK_METHODDEF
14797 OS_SCHED_GET_PRIORITY_MAX_METHODDEF
14798 OS_SCHED_GET_PRIORITY_MIN_METHODDEF
14799 OS_SCHED_GETPARAM_METHODDEF
14800 OS_SCHED_GETSCHEDULER_METHODDEF
14801 OS_SCHED_RR_GET_INTERVAL_METHODDEF
14802 OS_SCHED_SETPARAM_METHODDEF
14803 OS_SCHED_SETSCHEDULER_METHODDEF
14804 OS_SCHED_YIELD_METHODDEF
14805 OS_SCHED_SETAFFINITY_METHODDEF
14806 OS_SCHED_GETAFFINITY_METHODDEF
14807 OS_OPENPTY_METHODDEF
14808 OS_LOGIN_TTY_METHODDEF
14809 OS_FORKPTY_METHODDEF
14810 OS_GETEGID_METHODDEF
14811 OS_GETEUID_METHODDEF
14812 OS_GETGID_METHODDEF
14813 OS_GETGROUPLIST_METHODDEF
14814 OS_GETGROUPS_METHODDEF
14815 OS_GETPID_METHODDEF
14816 OS_GETPGRP_METHODDEF
14817 OS_GETPPID_METHODDEF
14818 OS_GETUID_METHODDEF
14819 OS_GETLOGIN_METHODDEF
14820 OS_KILL_METHODDEF
14821 OS_KILLPG_METHODDEF
14822 OS_PLOCK_METHODDEF
14823 OS_STARTFILE_METHODDEF
14824 OS_SETUID_METHODDEF
14825 OS_SETEUID_METHODDEF
14826 OS_SETREUID_METHODDEF
14827 OS_SETGID_METHODDEF
14828 OS_SETEGID_METHODDEF
14829 OS_SETREGID_METHODDEF
14830 OS_SETGROUPS_METHODDEF
14831 OS_INITGROUPS_METHODDEF
14832 OS_GETPGID_METHODDEF
14833 OS_SETPGRP_METHODDEF
14834 OS_WAIT_METHODDEF
14835 OS_WAIT3_METHODDEF
14836 OS_WAIT4_METHODDEF
14837 OS_WAITID_METHODDEF
14838 OS_WAITPID_METHODDEF
14839 OS_PIDFD_OPEN_METHODDEF
14840 OS_GETSID_METHODDEF
14841 OS_SETSID_METHODDEF
14842 OS_SETPGID_METHODDEF
14843 OS_TCGETPGRP_METHODDEF
14844 OS_TCSETPGRP_METHODDEF
14845 OS_OPEN_METHODDEF
14846 OS_CLOSE_METHODDEF
14847 OS_CLOSERANGE_METHODDEF
14848 OS_DEVICE_ENCODING_METHODDEF
14849 OS_DUP_METHODDEF
14850 OS_DUP2_METHODDEF
14851 OS_LOCKF_METHODDEF
14852 OS_LSEEK_METHODDEF
14853 OS_READ_METHODDEF
14854 OS_READV_METHODDEF
14855 OS_PREAD_METHODDEF
14856 OS_PREADV_METHODDEF
14857 OS_WRITE_METHODDEF
14858 OS_WRITEV_METHODDEF
14859 OS_PWRITE_METHODDEF
14860 OS_PWRITEV_METHODDEF
14861 OS_SENDFILE_METHODDEF
14862 OS_FSTAT_METHODDEF
14863 OS_ISATTY_METHODDEF
14864 OS_PIPE_METHODDEF
14865 OS_PIPE2_METHODDEF
14866 OS_MKFIFO_METHODDEF
14867 OS_MKNOD_METHODDEF
14868 OS_MAJOR_METHODDEF
14869 OS_MINOR_METHODDEF
14870 OS_MAKEDEV_METHODDEF
14871 OS_FTRUNCATE_METHODDEF
14872 OS_TRUNCATE_METHODDEF
14873 OS_POSIX_FALLOCATE_METHODDEF
14874 OS_POSIX_FADVISE_METHODDEF
14875 OS_PUTENV_METHODDEF
14876 OS_UNSETENV_METHODDEF
14877 OS_STRERROR_METHODDEF
14878 OS_FCHDIR_METHODDEF
14879 OS_FSYNC_METHODDEF
14880 OS_SYNC_METHODDEF
14881 OS_FDATASYNC_METHODDEF
14882 OS_WCOREDUMP_METHODDEF
14883 OS_WIFCONTINUED_METHODDEF
14884 OS_WIFSTOPPED_METHODDEF
14885 OS_WIFSIGNALED_METHODDEF
14886 OS_WIFEXITED_METHODDEF
14887 OS_WEXITSTATUS_METHODDEF
14888 OS_WTERMSIG_METHODDEF
14889 OS_WSTOPSIG_METHODDEF
14890 OS_FSTATVFS_METHODDEF
14891 OS_STATVFS_METHODDEF
14892 OS_CONFSTR_METHODDEF
14893 OS_SYSCONF_METHODDEF
14894 OS_FPATHCONF_METHODDEF
14895 OS_PATHCONF_METHODDEF
14896 OS_ABORT_METHODDEF
14897 OS__GETFULLPATHNAME_METHODDEF
14898 OS__GETDISKUSAGE_METHODDEF
14899 OS__GETFINALPATHNAME_METHODDEF
14900 OS__GETVOLUMEPATHNAME_METHODDEF
14901 OS__PATH_SPLITROOT_METHODDEF
14902 OS__PATH_NORMPATH_METHODDEF
14903 OS_GETLOADAVG_METHODDEF
14904 OS_URANDOM_METHODDEF
14905 OS_SETRESUID_METHODDEF
14906 OS_SETRESGID_METHODDEF
14907 OS_GETRESUID_METHODDEF
14908 OS_GETRESGID_METHODDEF
14909
14910 OS_GETXATTR_METHODDEF
14911 OS_SETXATTR_METHODDEF
14912 OS_REMOVEXATTR_METHODDEF
14913 OS_LISTXATTR_METHODDEF
14914
14915 OS_GET_TERMINAL_SIZE_METHODDEF
14916 OS_CPU_COUNT_METHODDEF
14917 OS_GET_INHERITABLE_METHODDEF
14918 OS_SET_INHERITABLE_METHODDEF
14919 OS_GET_HANDLE_INHERITABLE_METHODDEF
14920 OS_SET_HANDLE_INHERITABLE_METHODDEF
14921 OS_GET_BLOCKING_METHODDEF
14922 OS_SET_BLOCKING_METHODDEF
14923 OS_SCANDIR_METHODDEF
14924 OS_FSPATH_METHODDEF
14925 OS_GETRANDOM_METHODDEF
14926 OS_MEMFD_CREATE_METHODDEF
14927 OS_EVENTFD_METHODDEF
14928 OS_EVENTFD_READ_METHODDEF
14929 OS_EVENTFD_WRITE_METHODDEF
14930 OS__ADD_DLL_DIRECTORY_METHODDEF
14931 OS__REMOVE_DLL_DIRECTORY_METHODDEF
14932 OS_WAITSTATUS_TO_EXITCODE_METHODDEF
14933 {NULL, NULL} /* Sentinel */
14934 };
14935
14936 static int
14937 3404 all_ins(PyObject *m)
14938 {
14939 #ifdef F_OK
14940
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, F_OK)) return -1;
14941 #endif
14942 #ifdef R_OK
14943
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, R_OK)) return -1;
14944 #endif
14945 #ifdef W_OK
14946
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, W_OK)) return -1;
14947 #endif
14948 #ifdef X_OK
14949
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, X_OK)) return -1;
14950 #endif
14951 #ifdef NGROUPS_MAX
14952
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, NGROUPS_MAX)) return -1;
14953 #endif
14954 #ifdef TMP_MAX
14955
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, TMP_MAX)) return -1;
14956 #endif
14957 #ifdef WCONTINUED
14958
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, WCONTINUED)) return -1;
14959 #endif
14960 #ifdef WNOHANG
14961
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, WNOHANG)) return -1;
14962 #endif
14963 #ifdef WUNTRACED
14964
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, WUNTRACED)) return -1;
14965 #endif
14966 #ifdef O_RDONLY
14967
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, O_RDONLY)) return -1;
14968 #endif
14969 #ifdef O_WRONLY
14970
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, O_WRONLY)) return -1;
14971 #endif
14972 #ifdef O_RDWR
14973
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, O_RDWR)) return -1;
14974 #endif
14975 #ifdef O_NDELAY
14976
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, O_NDELAY)) return -1;
14977 #endif
14978 #ifdef O_NONBLOCK
14979
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, O_NONBLOCK)) return -1;
14980 #endif
14981 #ifdef O_APPEND
14982
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, O_APPEND)) return -1;
14983 #endif
14984 #ifdef O_DSYNC
14985
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, O_DSYNC)) return -1;
14986 #endif
14987 #ifdef O_RSYNC
14988
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, O_RSYNC)) return -1;
14989 #endif
14990 #ifdef O_SYNC
14991
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, O_SYNC)) return -1;
14992 #endif
14993 #ifdef O_NOCTTY
14994
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, O_NOCTTY)) return -1;
14995 #endif
14996 #ifdef O_CREAT
14997
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, O_CREAT)) return -1;
14998 #endif
14999 #ifdef O_EXCL
15000
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, O_EXCL)) return -1;
15001 #endif
15002 #ifdef O_TRUNC
15003
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, O_TRUNC)) return -1;
15004 #endif
15005 #ifdef O_BINARY
15006 if (PyModule_AddIntMacro(m, O_BINARY)) return -1;
15007 #endif
15008 #ifdef O_TEXT
15009 if (PyModule_AddIntMacro(m, O_TEXT)) return -1;
15010 #endif
15011 #ifdef O_XATTR
15012 if (PyModule_AddIntMacro(m, O_XATTR)) return -1;
15013 #endif
15014 #ifdef O_LARGEFILE
15015
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, O_LARGEFILE)) return -1;
15016 #endif
15017 #ifndef __GNU__
15018 #ifdef O_SHLOCK
15019 if (PyModule_AddIntMacro(m, O_SHLOCK)) return -1;
15020 #endif
15021 #ifdef O_EXLOCK
15022 if (PyModule_AddIntMacro(m, O_EXLOCK)) return -1;
15023 #endif
15024 #endif
15025 #ifdef O_EXEC
15026 if (PyModule_AddIntMacro(m, O_EXEC)) return -1;
15027 #endif
15028 #ifdef O_SEARCH
15029 if (PyModule_AddIntMacro(m, O_SEARCH)) return -1;
15030 #endif
15031 #ifdef O_PATH
15032
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, O_PATH)) return -1;
15033 #endif
15034 #ifdef O_TTY_INIT
15035 if (PyModule_AddIntMacro(m, O_TTY_INIT)) return -1;
15036 #endif
15037 #ifdef O_TMPFILE
15038
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, O_TMPFILE)) return -1;
15039 #endif
15040 #ifdef PRIO_PROCESS
15041
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, PRIO_PROCESS)) return -1;
15042 #endif
15043 #ifdef PRIO_PGRP
15044
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, PRIO_PGRP)) return -1;
15045 #endif
15046 #ifdef PRIO_USER
15047
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, PRIO_USER)) return -1;
15048 #endif
15049 #ifdef O_CLOEXEC
15050
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, O_CLOEXEC)) return -1;
15051 #endif
15052 #ifdef O_ACCMODE
15053
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, O_ACCMODE)) return -1;
15054 #endif
15055 #ifdef O_EVTONLY
15056 if (PyModule_AddIntMacro(m, O_EVTONLY)) return -1;
15057 #endif
15058 #ifdef O_FSYNC
15059
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, O_FSYNC)) return -1;
15060 #endif
15061 #ifdef O_SYMLINK
15062 if (PyModule_AddIntMacro(m, O_SYMLINK)) return -1;
15063 #endif
15064
15065 #ifdef SEEK_HOLE
15066
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, SEEK_HOLE)) return -1;
15067 #endif
15068 #ifdef SEEK_DATA
15069
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, SEEK_DATA)) return -1;
15070 #endif
15071
15072 /* MS Windows */
15073 #ifdef O_NOINHERIT
15074 /* Don't inherit in child processes. */
15075 if (PyModule_AddIntMacro(m, O_NOINHERIT)) return -1;
15076 #endif
15077 #ifdef _O_SHORT_LIVED
15078 /* Optimize for short life (keep in memory). */
15079 /* MS forgot to define this one with a non-underscore form too. */
15080 if (PyModule_AddIntConstant(m, "O_SHORT_LIVED", _O_SHORT_LIVED)) return -1;
15081 #endif
15082 #ifdef O_TEMPORARY
15083 /* Automatically delete when last handle is closed. */
15084 if (PyModule_AddIntMacro(m, O_TEMPORARY)) return -1;
15085 #endif
15086 #ifdef O_RANDOM
15087 /* Optimize for random access. */
15088 if (PyModule_AddIntMacro(m, O_RANDOM)) return -1;
15089 #endif
15090 #ifdef O_SEQUENTIAL
15091 /* Optimize for sequential access. */
15092 if (PyModule_AddIntMacro(m, O_SEQUENTIAL)) return -1;
15093 #endif
15094
15095 /* GNU extensions. */
15096 #ifdef O_ASYNC
15097 /* Send a SIGIO signal whenever input or output
15098 becomes available on file descriptor */
15099
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, O_ASYNC)) return -1;
15100 #endif
15101 #ifdef O_DIRECT
15102 /* Direct disk access. */
15103
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, O_DIRECT)) return -1;
15104 #endif
15105 #ifdef O_DIRECTORY
15106 /* Must be a directory. */
15107
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, O_DIRECTORY)) return -1;
15108 #endif
15109 #ifdef O_NOFOLLOW
15110 /* Do not follow links. */
15111
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, O_NOFOLLOW)) return -1;
15112 #endif
15113 #ifdef O_NOFOLLOW_ANY
15114 if (PyModule_AddIntMacro(m, O_NOFOLLOW_ANY)) return -1;
15115 #endif
15116 #ifdef O_NOLINKS
15117 /* Fails if link count of the named file is greater than 1 */
15118 if (PyModule_AddIntMacro(m, O_NOLINKS)) return -1;
15119 #endif
15120 #ifdef O_NOATIME
15121 /* Do not update the access time. */
15122
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, O_NOATIME)) return -1;
15123 #endif
15124
15125 /* These come from sysexits.h */
15126 #ifdef EX_OK
15127
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, EX_OK)) return -1;
15128 #endif /* EX_OK */
15129 #ifdef EX_USAGE
15130
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, EX_USAGE)) return -1;
15131 #endif /* EX_USAGE */
15132 #ifdef EX_DATAERR
15133
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, EX_DATAERR)) return -1;
15134 #endif /* EX_DATAERR */
15135 #ifdef EX_NOINPUT
15136
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, EX_NOINPUT)) return -1;
15137 #endif /* EX_NOINPUT */
15138 #ifdef EX_NOUSER
15139
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, EX_NOUSER)) return -1;
15140 #endif /* EX_NOUSER */
15141 #ifdef EX_NOHOST
15142
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, EX_NOHOST)) return -1;
15143 #endif /* EX_NOHOST */
15144 #ifdef EX_UNAVAILABLE
15145
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, EX_UNAVAILABLE)) return -1;
15146 #endif /* EX_UNAVAILABLE */
15147 #ifdef EX_SOFTWARE
15148
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, EX_SOFTWARE)) return -1;
15149 #endif /* EX_SOFTWARE */
15150 #ifdef EX_OSERR
15151
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, EX_OSERR)) return -1;
15152 #endif /* EX_OSERR */
15153 #ifdef EX_OSFILE
15154
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, EX_OSFILE)) return -1;
15155 #endif /* EX_OSFILE */
15156 #ifdef EX_CANTCREAT
15157
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, EX_CANTCREAT)) return -1;
15158 #endif /* EX_CANTCREAT */
15159 #ifdef EX_IOERR
15160
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, EX_IOERR)) return -1;
15161 #endif /* EX_IOERR */
15162 #ifdef EX_TEMPFAIL
15163
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, EX_TEMPFAIL)) return -1;
15164 #endif /* EX_TEMPFAIL */
15165 #ifdef EX_PROTOCOL
15166
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, EX_PROTOCOL)) return -1;
15167 #endif /* EX_PROTOCOL */
15168 #ifdef EX_NOPERM
15169
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, EX_NOPERM)) return -1;
15170 #endif /* EX_NOPERM */
15171 #ifdef EX_CONFIG
15172
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, EX_CONFIG)) return -1;
15173 #endif /* EX_CONFIG */
15174 #ifdef EX_NOTFOUND
15175 if (PyModule_AddIntMacro(m, EX_NOTFOUND)) return -1;
15176 #endif /* EX_NOTFOUND */
15177
15178 /* statvfs */
15179 #ifdef ST_RDONLY
15180
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, ST_RDONLY)) return -1;
15181 #endif /* ST_RDONLY */
15182 #ifdef ST_NOSUID
15183
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, ST_NOSUID)) return -1;
15184 #endif /* ST_NOSUID */
15185
15186 /* GNU extensions */
15187 #ifdef ST_NODEV
15188
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, ST_NODEV)) return -1;
15189 #endif /* ST_NODEV */
15190 #ifdef ST_NOEXEC
15191
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, ST_NOEXEC)) return -1;
15192 #endif /* ST_NOEXEC */
15193 #ifdef ST_SYNCHRONOUS
15194
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, ST_SYNCHRONOUS)) return -1;
15195 #endif /* ST_SYNCHRONOUS */
15196 #ifdef ST_MANDLOCK
15197
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, ST_MANDLOCK)) return -1;
15198 #endif /* ST_MANDLOCK */
15199 #ifdef ST_WRITE
15200
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, ST_WRITE)) return -1;
15201 #endif /* ST_WRITE */
15202 #ifdef ST_APPEND
15203
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, ST_APPEND)) return -1;
15204 #endif /* ST_APPEND */
15205 #ifdef ST_NOATIME
15206
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, ST_NOATIME)) return -1;
15207 #endif /* ST_NOATIME */
15208 #ifdef ST_NODIRATIME
15209
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, ST_NODIRATIME)) return -1;
15210 #endif /* ST_NODIRATIME */
15211 #ifdef ST_RELATIME
15212
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, ST_RELATIME)) return -1;
15213 #endif /* ST_RELATIME */
15214
15215 /* FreeBSD sendfile() constants */
15216 #ifdef SF_NODISKIO
15217 if (PyModule_AddIntMacro(m, SF_NODISKIO)) return -1;
15218 #endif
15219 /* is obsolete since the 11.x release */
15220 #ifdef SF_MNOWAIT
15221 if (PyModule_AddIntMacro(m, SF_MNOWAIT)) return -1;
15222 #endif
15223 #ifdef SF_SYNC
15224 if (PyModule_AddIntMacro(m, SF_SYNC)) return -1;
15225 #endif
15226 #ifdef SF_NOCACHE
15227 if (PyModule_AddIntMacro(m, SF_NOCACHE)) return -1;
15228 #endif
15229
15230 /* constants for posix_fadvise */
15231 #ifdef POSIX_FADV_NORMAL
15232
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, POSIX_FADV_NORMAL)) return -1;
15233 #endif
15234 #ifdef POSIX_FADV_SEQUENTIAL
15235
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, POSIX_FADV_SEQUENTIAL)) return -1;
15236 #endif
15237 #ifdef POSIX_FADV_RANDOM
15238
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, POSIX_FADV_RANDOM)) return -1;
15239 #endif
15240 #ifdef POSIX_FADV_NOREUSE
15241
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, POSIX_FADV_NOREUSE)) return -1;
15242 #endif
15243 #ifdef POSIX_FADV_WILLNEED
15244
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, POSIX_FADV_WILLNEED)) return -1;
15245 #endif
15246 #ifdef POSIX_FADV_DONTNEED
15247
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, POSIX_FADV_DONTNEED)) return -1;
15248 #endif
15249
15250 /* constants for waitid */
15251 #if defined(HAVE_SYS_WAIT_H) && defined(HAVE_WAITID)
15252
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, P_PID)) return -1;
15253
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, P_PGID)) return -1;
15254
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, P_ALL)) return -1;
15255 #ifdef P_PIDFD
15256
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, P_PIDFD)) return -1;
15257 #endif
15258 #ifdef PIDFD_NONBLOCK
15259 if (PyModule_AddIntMacro(m, PIDFD_NONBLOCK)) return -1;
15260 #endif
15261 #endif
15262 #ifdef WEXITED
15263
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, WEXITED)) return -1;
15264 #endif
15265 #ifdef WNOWAIT
15266
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, WNOWAIT)) return -1;
15267 #endif
15268 #ifdef WSTOPPED
15269
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, WSTOPPED)) return -1;
15270 #endif
15271 #ifdef CLD_EXITED
15272
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, CLD_EXITED)) return -1;
15273 #endif
15274 #ifdef CLD_KILLED
15275
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, CLD_KILLED)) return -1;
15276 #endif
15277 #ifdef CLD_DUMPED
15278
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, CLD_DUMPED)) return -1;
15279 #endif
15280 #ifdef CLD_TRAPPED
15281
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, CLD_TRAPPED)) return -1;
15282 #endif
15283 #ifdef CLD_STOPPED
15284
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, CLD_STOPPED)) return -1;
15285 #endif
15286 #ifdef CLD_CONTINUED
15287
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, CLD_CONTINUED)) return -1;
15288 #endif
15289
15290 /* constants for lockf */
15291 #ifdef F_LOCK
15292
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, F_LOCK)) return -1;
15293 #endif
15294 #ifdef F_TLOCK
15295
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, F_TLOCK)) return -1;
15296 #endif
15297 #ifdef F_ULOCK
15298
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, F_ULOCK)) return -1;
15299 #endif
15300 #ifdef F_TEST
15301
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, F_TEST)) return -1;
15302 #endif
15303
15304 #ifdef RWF_DSYNC
15305
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntConstant(m, "RWF_DSYNC", RWF_DSYNC)) return -1;
15306 #endif
15307 #ifdef RWF_HIPRI
15308
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntConstant(m, "RWF_HIPRI", RWF_HIPRI)) return -1;
15309 #endif
15310 #ifdef RWF_SYNC
15311
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntConstant(m, "RWF_SYNC", RWF_SYNC)) return -1;
15312 #endif
15313 #ifdef RWF_NOWAIT
15314
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntConstant(m, "RWF_NOWAIT", RWF_NOWAIT)) return -1;
15315 #endif
15316 #ifdef RWF_APPEND
15317
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntConstant(m, "RWF_APPEND", RWF_APPEND)) return -1;
15318 #endif
15319
15320 /* constants for splice */
15321 #if defined(HAVE_SPLICE) && defined(__linux__)
15322
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntConstant(m, "SPLICE_F_MOVE", SPLICE_F_MOVE)) return -1;
15323
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntConstant(m, "SPLICE_F_NONBLOCK", SPLICE_F_NONBLOCK)) return -1;
15324
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntConstant(m, "SPLICE_F_MORE", SPLICE_F_MORE)) return -1;
15325 #endif
15326
15327 /* constants for posix_spawn */
15328 #ifdef HAVE_POSIX_SPAWN
15329
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntConstant(m, "POSIX_SPAWN_OPEN", POSIX_SPAWN_OPEN)) return -1;
15330
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntConstant(m, "POSIX_SPAWN_CLOSE", POSIX_SPAWN_CLOSE)) return -1;
15331
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntConstant(m, "POSIX_SPAWN_DUP2", POSIX_SPAWN_DUP2)) return -1;
15332 #endif
15333
15334 #if defined(HAVE_SPAWNV) || defined (HAVE_RTPSPAWN)
15335 if (PyModule_AddIntConstant(m, "P_WAIT", _P_WAIT)) return -1;
15336 if (PyModule_AddIntConstant(m, "P_NOWAIT", _P_NOWAIT)) return -1;
15337 if (PyModule_AddIntConstant(m, "P_NOWAITO", _P_NOWAITO)) return -1;
15338 #endif
15339 #ifdef HAVE_SPAWNV
15340 if (PyModule_AddIntConstant(m, "P_OVERLAY", _OLD_P_OVERLAY)) return -1;
15341 if (PyModule_AddIntConstant(m, "P_DETACH", _P_DETACH)) return -1;
15342 #endif
15343
15344 #ifdef HAVE_SCHED_H
15345 #ifdef SCHED_OTHER
15346
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, SCHED_OTHER)) return -1;
15347 #endif
15348 #ifdef SCHED_FIFO
15349
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, SCHED_FIFO)) return -1;
15350 #endif
15351 #ifdef SCHED_RR
15352
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, SCHED_RR)) return -1;
15353 #endif
15354 #ifdef SCHED_SPORADIC
15355 if (PyModule_AddIntMacro(m, SCHED_SPORADIC)) return -1;
15356 #endif
15357 #ifdef SCHED_BATCH
15358
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, SCHED_BATCH)) return -1;
15359 #endif
15360 #ifdef SCHED_IDLE
15361
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, SCHED_IDLE)) return -1;
15362 #endif
15363 #ifdef SCHED_RESET_ON_FORK
15364
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, SCHED_RESET_ON_FORK)) return -1;
15365 #endif
15366 #ifdef SCHED_SYS
15367 if (PyModule_AddIntMacro(m, SCHED_SYS)) return -1;
15368 #endif
15369 #ifdef SCHED_IA
15370 if (PyModule_AddIntMacro(m, SCHED_IA)) return -1;
15371 #endif
15372 #ifdef SCHED_FSS
15373 if (PyModule_AddIntMacro(m, SCHED_FSS)) return -1;
15374 #endif
15375 #ifdef SCHED_FX
15376 if (PyModule_AddIntConstant(m, "SCHED_FX", SCHED_FSS)) return -1;
15377 #endif
15378 #endif
15379
15380 #ifdef USE_XATTRS
15381
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, XATTR_CREATE)) return -1;
15382
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, XATTR_REPLACE)) return -1;
15383
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, XATTR_SIZE_MAX)) return -1;
15384 #endif
15385
15386 #if HAVE_DECL_RTLD_LAZY
15387
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, RTLD_LAZY)) return -1;
15388 #endif
15389 #if HAVE_DECL_RTLD_NOW
15390
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, RTLD_NOW)) return -1;
15391 #endif
15392 #if HAVE_DECL_RTLD_GLOBAL
15393
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, RTLD_GLOBAL)) return -1;
15394 #endif
15395 #if HAVE_DECL_RTLD_LOCAL
15396
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, RTLD_LOCAL)) return -1;
15397 #endif
15398 #if HAVE_DECL_RTLD_NODELETE
15399
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, RTLD_NODELETE)) return -1;
15400 #endif
15401 #if HAVE_DECL_RTLD_NOLOAD
15402
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, RTLD_NOLOAD)) return -1;
15403 #endif
15404 #if HAVE_DECL_RTLD_DEEPBIND
15405
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, RTLD_DEEPBIND)) return -1;
15406 #endif
15407 #if HAVE_DECL_RTLD_MEMBER
15408 if (PyModule_AddIntMacro(m, RTLD_MEMBER)) return -1;
15409 #endif
15410
15411 #ifdef HAVE_GETRANDOM_SYSCALL
15412
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, GRND_RANDOM)) return -1;
15413
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, GRND_NONBLOCK)) return -1;
15414 #endif
15415 #ifdef HAVE_MEMFD_CREATE
15416
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, MFD_CLOEXEC)) return -1;
15417
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, MFD_ALLOW_SEALING)) return -1;
15418 #ifdef MFD_HUGETLB
15419
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, MFD_HUGETLB)) return -1;
15420 #endif
15421 #ifdef MFD_HUGE_SHIFT
15422
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, MFD_HUGE_SHIFT)) return -1;
15423 #endif
15424 #ifdef MFD_HUGE_MASK
15425
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, MFD_HUGE_MASK)) return -1;
15426 #endif
15427 #ifdef MFD_HUGE_64KB
15428
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, MFD_HUGE_64KB)) return -1;
15429 #endif
15430 #ifdef MFD_HUGE_512KB
15431
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, MFD_HUGE_512KB)) return -1;
15432 #endif
15433 #ifdef MFD_HUGE_1MB
15434
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, MFD_HUGE_1MB)) return -1;
15435 #endif
15436 #ifdef MFD_HUGE_2MB
15437
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, MFD_HUGE_2MB)) return -1;
15438 #endif
15439 #ifdef MFD_HUGE_8MB
15440
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, MFD_HUGE_8MB)) return -1;
15441 #endif
15442 #ifdef MFD_HUGE_16MB
15443
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, MFD_HUGE_16MB)) return -1;
15444 #endif
15445 #ifdef MFD_HUGE_32MB
15446
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, MFD_HUGE_32MB)) return -1;
15447 #endif
15448 #ifdef MFD_HUGE_256MB
15449
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, MFD_HUGE_256MB)) return -1;
15450 #endif
15451 #ifdef MFD_HUGE_512MB
15452
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, MFD_HUGE_512MB)) return -1;
15453 #endif
15454 #ifdef MFD_HUGE_1GB
15455
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, MFD_HUGE_1GB)) return -1;
15456 #endif
15457 #ifdef MFD_HUGE_2GB
15458
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, MFD_HUGE_2GB)) return -1;
15459 #endif
15460 #ifdef MFD_HUGE_16GB
15461
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, MFD_HUGE_16GB)) return -1;
15462 #endif
15463 #endif /* HAVE_MEMFD_CREATE */
15464
15465 #ifdef HAVE_EVENTFD
15466
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, EFD_CLOEXEC)) return -1;
15467
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, EFD_NONBLOCK)) return -1;
15468
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (PyModule_AddIntMacro(m, EFD_SEMAPHORE)) return -1;
15469 #endif
15470
15471 #if defined(__APPLE__)
15472 if (PyModule_AddIntConstant(m, "_COPYFILE_DATA", COPYFILE_DATA)) return -1;
15473 if (PyModule_AddIntConstant(m, "_COPYFILE_STAT", COPYFILE_STAT)) return -1;
15474 if (PyModule_AddIntConstant(m, "_COPYFILE_ACL", COPYFILE_ACL)) return -1;
15475 if (PyModule_AddIntConstant(m, "_COPYFILE_XATTR", COPYFILE_XATTR)) return -1;
15476 #endif
15477
15478 #ifdef MS_WINDOWS
15479 if (PyModule_AddIntConstant(m, "_LOAD_LIBRARY_SEARCH_DEFAULT_DIRS", LOAD_LIBRARY_SEARCH_DEFAULT_DIRS)) return -1;
15480 if (PyModule_AddIntConstant(m, "_LOAD_LIBRARY_SEARCH_APPLICATION_DIR", LOAD_LIBRARY_SEARCH_APPLICATION_DIR)) return -1;
15481 if (PyModule_AddIntConstant(m, "_LOAD_LIBRARY_SEARCH_SYSTEM32", LOAD_LIBRARY_SEARCH_SYSTEM32)) return -1;
15482 if (PyModule_AddIntConstant(m, "_LOAD_LIBRARY_SEARCH_USER_DIRS", LOAD_LIBRARY_SEARCH_USER_DIRS)) return -1;
15483 if (PyModule_AddIntConstant(m, "_LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR", LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR)) return -1;
15484 #endif
15485
15486 3404 return 0;
15487 }
15488
15489
15490
15491 #define PROBE(name, test) \
15492 static int name(void) \
15493 { \
15494 if (test) { \
15495 return 1; \
15496 } else { \
15497 return 0; \
15498 } \
15499 }
15500
15501 #ifdef HAVE_FSTATAT
15502 3404 PROBE(probe_fstatat, HAVE_FSTATAT_RUNTIME)
15503 #endif
15504
15505 #ifdef HAVE_FACCESSAT
15506 3404 PROBE(probe_faccessat, HAVE_FACCESSAT_RUNTIME)
15507 #endif
15508
15509 #ifdef HAVE_FCHMODAT
15510 3404 PROBE(probe_fchmodat, HAVE_FCHMODAT_RUNTIME)
15511 #endif
15512
15513 #ifdef HAVE_FCHOWNAT
15514 3404 PROBE(probe_fchownat, HAVE_FCHOWNAT_RUNTIME)
15515 #endif
15516
15517 #ifdef HAVE_LINKAT
15518 3404 PROBE(probe_linkat, HAVE_LINKAT_RUNTIME)
15519 #endif
15520
15521 #ifdef HAVE_FDOPENDIR
15522 3404 PROBE(probe_fdopendir, HAVE_FDOPENDIR_RUNTIME)
15523 #endif
15524
15525 #ifdef HAVE_MKDIRAT
15526 3404 PROBE(probe_mkdirat, HAVE_MKDIRAT_RUNTIME)
15527 #endif
15528
15529 #ifdef HAVE_RENAMEAT
15530 3404 PROBE(probe_renameat, HAVE_RENAMEAT_RUNTIME)
15531 #endif
15532
15533 #ifdef HAVE_UNLINKAT
15534 3404 PROBE(probe_unlinkat, HAVE_UNLINKAT_RUNTIME)
15535 #endif
15536
15537 #ifdef HAVE_OPENAT
15538 3404 PROBE(probe_openat, HAVE_OPENAT_RUNTIME)
15539 #endif
15540
15541 #ifdef HAVE_READLINKAT
15542 3404 PROBE(probe_readlinkat, HAVE_READLINKAT_RUNTIME)
15543 #endif
15544
15545 #ifdef HAVE_SYMLINKAT
15546 3404 PROBE(probe_symlinkat, HAVE_SYMLINKAT_RUNTIME)
15547 #endif
15548
15549 #ifdef HAVE_FUTIMENS
15550 3404 PROBE(probe_futimens, HAVE_FUTIMENS_RUNTIME)
15551 #endif
15552
15553 #ifdef HAVE_UTIMENSAT
15554 3404 PROBE(probe_utimensat, HAVE_UTIMENSAT_RUNTIME)
15555 #endif
15556
15557
15558
15559
15560 static const struct have_function {
15561 const char * const label;
15562 int (*probe)(void);
15563 } have_functions[] = {
15564
15565 #ifdef HAVE_EVENTFD
15566 {"HAVE_EVENTFD", NULL},
15567 #endif
15568
15569 #ifdef HAVE_FACCESSAT
15570 { "HAVE_FACCESSAT", probe_faccessat },
15571 #endif
15572
15573 #ifdef HAVE_FCHDIR
15574 { "HAVE_FCHDIR", NULL },
15575 #endif
15576
15577 #ifdef HAVE_FCHMOD
15578 { "HAVE_FCHMOD", NULL },
15579 #endif
15580
15581 #ifdef HAVE_FCHMODAT
15582 { "HAVE_FCHMODAT", probe_fchmodat },
15583 #endif
15584
15585 #ifdef HAVE_FCHOWN
15586 { "HAVE_FCHOWN", NULL },
15587 #endif
15588
15589 #ifdef HAVE_FCHOWNAT
15590 { "HAVE_FCHOWNAT", probe_fchownat },
15591 #endif
15592
15593 #ifdef HAVE_FEXECVE
15594 { "HAVE_FEXECVE", NULL },
15595 #endif
15596
15597 #ifdef HAVE_FDOPENDIR
15598 { "HAVE_FDOPENDIR", probe_fdopendir },
15599 #endif
15600
15601 #ifdef HAVE_FPATHCONF
15602 { "HAVE_FPATHCONF", NULL },
15603 #endif
15604
15605 #ifdef HAVE_FSTATAT
15606 { "HAVE_FSTATAT", probe_fstatat },
15607 #endif
15608
15609 #ifdef HAVE_FSTATVFS
15610 { "HAVE_FSTATVFS", NULL },
15611 #endif
15612
15613 #if defined HAVE_FTRUNCATE || defined MS_WINDOWS
15614 { "HAVE_FTRUNCATE", NULL },
15615 #endif
15616
15617 #ifdef HAVE_FUTIMENS
15618 { "HAVE_FUTIMENS", probe_futimens },
15619 #endif
15620
15621 #ifdef HAVE_FUTIMES
15622 { "HAVE_FUTIMES", NULL },
15623 #endif
15624
15625 #ifdef HAVE_FUTIMESAT
15626 { "HAVE_FUTIMESAT", NULL },
15627 #endif
15628
15629 #ifdef HAVE_LINKAT
15630 { "HAVE_LINKAT", probe_linkat },
15631 #endif
15632
15633 #ifdef HAVE_LCHFLAGS
15634 { "HAVE_LCHFLAGS", NULL },
15635 #endif
15636
15637 #ifdef HAVE_LCHMOD
15638 { "HAVE_LCHMOD", NULL },
15639 #endif
15640
15641 #ifdef HAVE_LCHOWN
15642 { "HAVE_LCHOWN", NULL },
15643 #endif
15644
15645 #ifdef HAVE_LSTAT
15646 { "HAVE_LSTAT", NULL },
15647 #endif
15648
15649 #ifdef HAVE_LUTIMES
15650 { "HAVE_LUTIMES", NULL },
15651 #endif
15652
15653 #ifdef HAVE_MEMFD_CREATE
15654 { "HAVE_MEMFD_CREATE", NULL },
15655 #endif
15656
15657 #ifdef HAVE_MKDIRAT
15658 { "HAVE_MKDIRAT", probe_mkdirat },
15659 #endif
15660
15661 #ifdef HAVE_MKFIFOAT
15662 { "HAVE_MKFIFOAT", NULL },
15663 #endif
15664
15665 #ifdef HAVE_MKNODAT
15666 { "HAVE_MKNODAT", NULL },
15667 #endif
15668
15669 #ifdef HAVE_OPENAT
15670 { "HAVE_OPENAT", probe_openat },
15671 #endif
15672
15673 #ifdef HAVE_READLINKAT
15674 { "HAVE_READLINKAT", probe_readlinkat },
15675 #endif
15676
15677 #ifdef HAVE_RENAMEAT
15678 { "HAVE_RENAMEAT", probe_renameat },
15679 #endif
15680
15681 #ifdef HAVE_SYMLINKAT
15682 { "HAVE_SYMLINKAT", probe_symlinkat },
15683 #endif
15684
15685 #ifdef HAVE_UNLINKAT
15686 { "HAVE_UNLINKAT", probe_unlinkat },
15687 #endif
15688
15689 #ifdef HAVE_UTIMENSAT
15690 { "HAVE_UTIMENSAT", probe_utimensat },
15691 #endif
15692
15693 #ifdef MS_WINDOWS
15694 { "MS_WINDOWS", NULL },
15695 #endif
15696
15697 { NULL, NULL }
15698 };
15699
15700
15701 static int
15702 3404 posixmodule_exec(PyObject *m)
15703 {
15704 3404 _posixstate *state = get_posix_state(m);
15705
15706 #if defined(HAVE_PWRITEV)
15707 if (HAVE_PWRITEV_RUNTIME) {} else {
15708 PyObject* dct = PyModule_GetDict(m);
15709
15710 if (dct == NULL) {
15711 return -1;
15712 }
15713
15714 if (PyDict_DelItemString(dct, "pwritev") == -1) {
15715 PyErr_Clear();
15716 }
15717 if (PyDict_DelItemString(dct, "preadv") == -1) {
15718 PyErr_Clear();
15719 }
15720 }
15721 #endif
15722
15723 /* Initialize environ dictionary */
15724 3404 PyObject *v = convertenviron();
15725 3404 Py_XINCREF(v);
15726
2/4
✓ Branch 0 taken 3404 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 3404 times.
3404 if (v == NULL || PyModule_AddObject(m, "environ", v) != 0)
15727 return -1;
15728 3404 Py_DECREF(v);
15729
15730
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (all_ins(m))
15731 return -1;
15732
15733
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if (setup_confname_tables(m))
15734 return -1;
15735
15736 3404 Py_INCREF(PyExc_OSError);
15737 3404 PyModule_AddObject(m, "error", PyExc_OSError);
15738
15739 #if defined(HAVE_WAITID) && !defined(__APPLE__)
15740 3404 waitid_result_desc.name = MODNAME ".waitid_result";
15741 3404 PyObject *WaitidResultType = (PyObject *)PyStructSequence_NewType(&waitid_result_desc);
15742
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3404 times.
3404 if (WaitidResultType == NULL) {
15743 return -1;
15744 }
15745 3404 Py_INCREF(WaitidResultType);
15746 3404 PyModule_AddObject(m, "waitid_result", WaitidResultType);
15747 3404 state->WaitidResultType = WaitidResultType;
15748 #endif
15749
15750 3404 stat_result_desc.name = "os.stat_result"; /* see issue #19209 */
15751 3404 stat_result_desc.fields[7].name = PyStructSequence_UnnamedField;
15752 3404 stat_result_desc.fields[8].name = PyStructSequence_UnnamedField;
15753 3404 stat_result_desc.fields[9].name = PyStructSequence_UnnamedField;
15754 3404 PyObject *StatResultType = (PyObject *)PyStructSequence_NewType(&stat_result_desc);
15755
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3404 times.
3404 if (StatResultType == NULL) {
15756 return -1;
15757 }
15758 3404 Py_INCREF(StatResultType);
15759 3404 PyModule_AddObject(m, "stat_result", StatResultType);
15760 3404 state->StatResultType = StatResultType;
15761 3404 structseq_new = ((PyTypeObject *)StatResultType)->tp_new;
15762 3404 ((PyTypeObject *)StatResultType)->tp_new = statresult_new;
15763
15764 3404 statvfs_result_desc.name = "os.statvfs_result"; /* see issue #19209 */
15765 3404 PyObject *StatVFSResultType = (PyObject *)PyStructSequence_NewType(&statvfs_result_desc);
15766
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3404 times.
3404 if (StatVFSResultType == NULL) {
15767 return -1;
15768 }
15769 3404 Py_INCREF(StatVFSResultType);
15770 3404 PyModule_AddObject(m, "statvfs_result", StatVFSResultType);
15771 3404 state->StatVFSResultType = StatVFSResultType;
15772 #ifdef NEED_TICKS_PER_SECOND
15773 # if defined(HAVE_SYSCONF) && defined(_SC_CLK_TCK)
15774 3404 ticks_per_second = sysconf(_SC_CLK_TCK);
15775 # elif defined(HZ)
15776 ticks_per_second = HZ;
15777 # else
15778 ticks_per_second = 60; /* magic fallback value; may be bogus */
15779 # endif
15780 #endif
15781
15782 #if defined(HAVE_SCHED_SETPARAM) || defined(HAVE_SCHED_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDPARAM)
15783 3404 sched_param_desc.name = MODNAME ".sched_param";
15784 3404 PyObject *SchedParamType = (PyObject *)PyStructSequence_NewType(&sched_param_desc);
15785
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3404 times.
3404 if (SchedParamType == NULL) {
15786 return -1;
15787 }
15788 3404 Py_INCREF(SchedParamType);
15789 3404 PyModule_AddObject(m, "sched_param", SchedParamType);
15790 3404 state->SchedParamType = SchedParamType;
15791 3404 ((PyTypeObject *)SchedParamType)->tp_new = os_sched_param;
15792 #endif
15793
15794 /* initialize TerminalSize_info */
15795 3404 PyObject *TerminalSizeType = (PyObject *)PyStructSequence_NewType(&TerminalSize_desc);
15796
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3404 times.
3404 if (TerminalSizeType == NULL) {
15797 return -1;
15798 }
15799 3404 Py_INCREF(TerminalSizeType);
15800 3404 PyModule_AddObject(m, "terminal_size", TerminalSizeType);
15801 3404 state->TerminalSizeType = TerminalSizeType;
15802
15803 /* initialize scandir types */
15804 3404 PyObject *ScandirIteratorType = PyType_FromModuleAndSpec(m, &ScandirIteratorType_spec, NULL);
15805
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3404 times.
3404 if (ScandirIteratorType == NULL) {
15806 return -1;
15807 }
15808 3404 state->ScandirIteratorType = ScandirIteratorType;
15809
15810 3404 PyObject *DirEntryType = PyType_FromModuleAndSpec(m, &DirEntryType_spec, NULL);
15811
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3404 times.
3404 if (DirEntryType == NULL) {
15812 return -1;
15813 }
15814 3404 Py_INCREF(DirEntryType);
15815 3404 PyModule_AddObject(m, "DirEntry", DirEntryType);
15816 3404 state->DirEntryType = DirEntryType;
15817
15818 3404 times_result_desc.name = MODNAME ".times_result";
15819 3404 PyObject *TimesResultType = (PyObject *)PyStructSequence_NewType(&times_result_desc);
15820
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3404 times.
3404 if (TimesResultType == NULL) {
15821 return -1;
15822 }
15823 3404 Py_INCREF(TimesResultType);
15824 3404 PyModule_AddObject(m, "times_result", TimesResultType);
15825 3404 state->TimesResultType = TimesResultType;
15826
15827 3404 PyTypeObject *UnameResultType = PyStructSequence_NewType(&uname_result_desc);
15828
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3404 times.
3404 if (UnameResultType == NULL) {
15829 return -1;
15830 }
15831 3404 Py_INCREF(UnameResultType);
15832 3404 PyModule_AddObject(m, "uname_result", (PyObject *)UnameResultType);
15833 3404 state->UnameResultType = (PyObject *)UnameResultType;
15834
15835
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3404 times.
3404 if ((state->billion = PyLong_FromLong(1000000000)) == NULL)
15836 return -1;
15837 #if defined(HAVE_WAIT3) || defined(HAVE_WAIT4)
15838 3404 state->struct_rusage = PyUnicode_InternFromString("struct_rusage");
15839
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3404 times.
3404 if (state->struct_rusage == NULL)
15840 return -1;
15841 #endif
15842 3404 state->st_mode = PyUnicode_InternFromString("st_mode");
15843
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3404 times.
3404 if (state->st_mode == NULL)
15844 return -1;
15845
15846 /* suppress "function not used" warnings */
15847 {
15848 int ignored;
15849 3404 fd_specified("", -1);
15850 3404 follow_symlinks_specified("", 1);
15851 3404 dir_fd_and_follow_symlinks_invalid("chmod", DEFAULT_DIR_FD, 1);
15852 3404 dir_fd_converter(Py_None, &ignored);
15853 3404 dir_fd_unavailable(Py_None, &ignored);
15854 }
15855
15856 /*
15857 * provide list of locally available functions
15858 * so os.py can populate support_* lists
15859 */
15860 3404 PyObject *list = PyList_New(0);
15861
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3404 times.
3404 if (!list) {
15862 return -1;
15863 }
15864
2/2
✓ Branch 0 taken 102120 times.
✓ Branch 1 taken 3404 times.
105524 for (const struct have_function *trace = have_functions; trace->label; trace++) {
15865 PyObject *unicode;
15866
3/4
✓ Branch 0 taken 47656 times.
✓ Branch 1 taken 54464 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 47656 times.
102120 if (trace->probe && !trace->probe()) continue;
15867 102120 unicode = PyUnicode_DecodeASCII(trace->label, strlen(trace->label), NULL);
15868
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 102120 times.
102120 if (!unicode)
15869 return -1;
15870
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 102120 times.
102120 if (PyList_Append(list, unicode))
15871 return -1;
15872 102120 Py_DECREF(unicode);
15873 }
15874
15875 3404 PyModule_AddObject(m, "_have_functions", list);
15876
15877 3404 return 0;
15878 }
15879
15880
15881 static PyModuleDef_Slot posixmodile_slots[] = {
15882 {Py_mod_exec, posixmodule_exec},
15883 {0, NULL}
15884 };
15885
15886 static struct PyModuleDef posixmodule = {
15887 PyModuleDef_HEAD_INIT,
15888 .m_name = MODNAME,
15889 .m_doc = posix__doc__,
15890 .m_size = sizeof(_posixstate),
15891 .m_methods = posix_methods,
15892 .m_slots = posixmodile_slots,
15893 .m_traverse = _posix_traverse,
15894 .m_clear = _posix_clear,
15895 .m_free = _posix_free,
15896 };
15897
15898 PyMODINIT_FUNC
15899 3404 INITFUNC(void)
15900 {
15901 3404 return PyModuleDef_Init(&posixmodule);
15902 }
15903
15904 #ifdef __cplusplus
15905 }
15906 #endif
15907